加入对telnet协议的支持,可以正常连接远程主机,还差录像数据没有记录。

pull/105/head
Apex Liu 2018-04-06 06:56:37 +08:00
parent 761e5fa3b6
commit e920bf1895
25 changed files with 2797 additions and 20 deletions

View File

@ -0,0 +1,42 @@
cmake_minimum_required(VERSION 3.5)
project(tptelnet)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${Project_SOURCE_DIR}/../out/server/x64/bin")
aux_source_directory(. DIR_RDP_SRCS)
aux_source_directory(../../common DIR_RDP_SRCS)
aux_source_directory(../../../../common/libex/src DIR_RDP_SRCS)
list(REMOVE_ITEM DIR_RDP_SRCS "./dllmain.cpp")
list(REMOVE_ITEM DIR_RDP_SRCS "./stdafx.cpp")
include_directories(
../../../../common/libex/include
../../../../common/teleport
)
IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
include_directories(
../../../../external/linux/release/include
)
link_directories(../../../../external/linux/release/lib)
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
include_directories(
../../../../external/macos/release/include
)
link_directories(../../../../external/macos/release/lib)
ENDIF (CMAKE_SYSTEM_NAME MATCHES "Linux")
add_library(tptelnet SHARED ${DIR_RDP_SRCS})
IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
target_link_libraries(tptelnet uv mbedx509 mbedtls mbedcrypto dl pthread rt util)
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
target_link_libraries(tptelnet uv mbedx509 mbedtls mbedcrypto dl pthread util)
ENDIF (CMAKE_SYSTEM_NAME MATCHES "Linux")

View File

@ -0,0 +1,27 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#ifdef _DEBUG
#include <vld.h>
#endif
#pragma comment(lib, "userenv.lib") // for GetUserProfileDirectory()
#pragma comment(lib, "psapi.lib") // for GetProcessMemoryInfo()
#pragma comment(lib, "iphlpapi.lib") // for GetAdaptersAddresses()
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View File

@ -0,0 +1,16 @@
// stdafx.cpp : source file that includes just the standard includes
// tpssh.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
#include <ex.h>
#ifdef EX_OS_WIN32
//# pragma comment(lib, "libeay32.lib")
# pragma comment(lib, "ws2_32.lib")
#endif

View File

@ -0,0 +1,16 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// TODO: reference additional headers your program requires here

View File

@ -0,0 +1,11 @@
#pragma once
// Including SDKDDKVer.h defines the highest available Windows platform.
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
#include <winsdkver.h>
#define _WIN32_WINNT 0x0600 // WinVista
#include <SDKDDKVer.h>

View File

@ -0,0 +1,312 @@
#include "telnet_conn.h"
#include "telnet_session.h"
#include "../../common/ts_memstream.h"
#include "../../common/ts_const.h"
#include <teleport_const.h>
TelnetConn::TelnetConn(TelnetSession *sess, bool is_server_side) : m_session(sess), m_is_server(is_server_side) {
if (is_server_side) {
m_name = "cli<->tp";
m_state = TELNET_CONN_STATE_CONNECTED;
}
else {
m_name = "tp<->srv";
m_state = TELNET_CONN_STATE_FREE;
}
m_is_recving = false;
m_timer_running = false;
uv_tcp_init(sess->get_loop(), &m_handle);
m_handle.data = this;
}
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);
m_session->close(TP_SESS_STAT_ERR_IO);
return false;
}
m_is_recving = true;
return true;
}
void TelnetConn::close() {
if (m_state == TELNET_CONN_STATE_FREE || m_state == TELNET_CONN_STATE_CLOSING)
return;
if (m_timer_running) {
m_timer_running = false;
uv_timer_stop(&m_timer_connect_timeout);
EXLOGW("[telnet] [%s] try to close while it connecting.\n", m_name);
m_state = TELNET_CONN_STATE_CLOSING;
uv_close(handle(), NULL);
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_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();
}
void TelnetConn::_on_alloc(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
TelnetConn *_this = (TelnetConn *) handle->data;
buf->base = (char *) calloc(1, suggested_size);
buf->len = suggested_size;
}
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) {
free(buf->base);
if (nread == -4077)
EXLOGD("[telnet] [%s] [recv] disconnected.\n", _this->m_name);
else if (nread == -104)
EXLOGD("[telnet] [%s] [recv] connection reset by peer.\n", _this->m_name);
else
EXLOGD("[telnet] [%s] [recv] nread=%d.\n", _this->m_name, nread);
_this->m_session->close(TP_SESS_STAT_END);
return;
}
else {
// #ifdef LOG_DATA
// if(!_this->m_session->is_relay())
// EXLOG_BIN((ex_u8*)buf->base, nread, "[telnet] [%s] RECV %d.", _this->m_name, nread);
// #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);
_this->m_session->do_next(_this);
}
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);
}
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);
// #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);
if (NULL == _data) {
free(w);
EXLOGE("[telnet] alloc buffer %dB failed.\n", size);
return false;
}
memcpy(_data, data, size);
uv_buf_t *_buf = (uv_buf_t *) calloc(1, sizeof(uv_buf_t));
_buf->base = (char *) _data;
_buf->len = size;
w->data = _buf;
if (0 == uv_write(w, (uv_stream_t *) &m_handle, _buf, 1, _on_send_done))
return true;
else {
EXLOGE("[telnet] [%s] raw_send() failed.\n", m_name);
return false;
}
}
void TelnetConn::_on_send_done(uv_write_t *req, int status) {
uv_buf_t *_buf = (uv_buf_t *) req->data;
free(_buf->base);
free(_buf);
free(req);
if (status == UV_ECANCELED) {
EXLOGE("[telnet] _on_send_done() got UV_ECANCELED.\n");
return;
}
}
void TelnetConn::connect(const char *server_ip, ex_u16 server_port) {
m_server_ip = server_ip;
m_server_port = server_port;
if (m_state == TELNET_CONN_STATE_CONNECTED) {
// 当前已经连接上了服务器了,断开重连
EXLOGV("[telnet] [%s] [%s] try to disconnect. %s:%d\n", m_name, m_session->client_addr(), server_ip, server_port);
m_state = TELNET_CONN_STATE_CLOSING;
uv_close((uv_handle_t *) &m_handle, _uv_on_reconnect);
return;
}
else {
EXLOGV("[telnet] [%s] [%s] try to connect to real TELNET server at %s:%d\n", m_name, m_session->client_addr(), server_ip, server_port);
}
struct sockaddr_in addr;
uv_ip4_addr(server_ip, server_port, &addr);
uv_connect_t *conn_req = (uv_connect_t *) calloc(1, sizeof(uv_connect_t));
conn_req->data = this;
// 设置一个超时回调,如果超时发生时连接尚未完成,就报错
uv_timer_init(m_session->get_loop(), &m_timer_connect_timeout);
m_timer_connect_timeout.data = this;
#ifdef EX_DEBUG
uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 5000, 0);
#else
uv_timer_start(&m_timer_connect_timeout, _uv_on_connect_timeout, 10000, 0);
#endif
m_timer_running = true;
//m_is_connecting = true;
m_state = TELNET_CONN_STATE_CONNECTING;
int err = 0;
if ((err = uv_tcp_connect(conn_req, &m_handle, (const struct sockaddr *) &addr, _uv_on_connected)) != 0) {
free(conn_req);
EXLOGE("[telnet] [%s] can not connect to server: %s\n", m_name, uv_strerror(err));
m_timer_running = false;
uv_timer_stop(&m_timer_connect_timeout);
uv_close((uv_handle_t*)&m_timer_connect_timeout, _uv_on_timer_connect_timeout_closed);
m_state = TELNET_CONN_STATE_FREE;
m_session->close(TP_SESS_STAT_ERR_CONNECT);
}
}
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;
uv_timer_stop(&_this->m_timer_connect_timeout);
uv_close((uv_handle_t*)&_this->m_timer_connect_timeout, _this->_uv_on_timer_connect_timeout_closed);
}
// 如果在连接成功之前就超时了,则关闭连接
EXLOGE("[telnet] [%s] timeout when connect to real TELNET server, cancel connection.\n", _this->m_name);
_this->m_state = TELNET_CONN_STATE_CLOSING;
uv_close(_this->handle(), _uv_on_closed);
}
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);
_this->m_handle.data = _this;
_this->connect(_this->m_server_ip.c_str(), _this->m_server_port);
}
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;
uv_timer_stop(&_this->m_timer_connect_timeout);
uv_close((uv_handle_t*)&_this->m_timer_connect_timeout, _this->_uv_on_timer_connect_timeout_closed);
}
if (status != 0) {
EXLOGE("[telnet] [%s] cannot connect to real TELNET server. %s\n", _this->m_name, uv_strerror(status));
_this->m_state = TELNET_CONN_STATE_FREE;
_this->m_session->close(TP_SESS_STAT_ERR_CONNECT);
return;
}
EXLOGW("[telnet] [%s] real TELNET server connected.\n", _this->m_session->client_addr());
_this->m_state = TELNET_CONN_STATE_CONNECTED;
if (!_this->start_recv()) {
_this->m_session->close(TP_SESS_STAT_ERR_IO);
return;
}
_this->m_session->do_next(_this, s_server_connected);
}
//static
void TelnetConn::_uv_on_timer_connect_timeout_closed(uv_handle_t *handle) {
}

View File

@ -0,0 +1,162 @@
#ifndef __TELNET_CONN_H__
#define __TELNET_CONN_H__
#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
#define TELNET_CONN_STATE_FREE 0 // not connected yet or closed
#define TELNET_CONN_STATE_CONNECTING 1 // connecting
#define TELNET_CONN_STATE_CONNECTED 2 // connected.
#define TELNET_CONN_STATE_CLOSING 3 // closing.
class TelnetSession;
class TelnetConn {
public:
TelnetConn(TelnetSession *sess, bool is_server_side);
~TelnetConn();
TelnetSession *session() { return m_session; }
// just for debug-info
const char *name() const { return m_name; }
bool is_server_side() const { return m_is_server; }
ex_u8 state() const { return m_state; }
uv_handle_t *handle() { return (uv_handle_t *) &m_handle; }
uv_tcp_t *tcp_handle() { return &m_handle; }
uv_stream_t *stream_handle() { return (uv_stream_t *) &m_handle; }
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.
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);
static void _on_send_done(uv_write_t *req, int status);
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;
bool m_is_server;
// for debug-info.
const char *m_name;
uv_tcp_t m_handle;
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
// 作为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

@ -0,0 +1,210 @@
#include "telnet_proxy.h"
#include "tpp_env.h"
#include <teleport_const.h>
TelnetProxy g_telnet_proxy;
TelnetProxy::TelnetProxy() : ExThreadBase("telnet-proxy-thread")
{
memset(&m_loop, 0, sizeof(uv_loop_t));
m_timer_counter = 0;
}
TelnetProxy::~TelnetProxy()
{
if (m_sessions.size() > 0)
EXLOGE("[telnet] not all session stopped.\n");
}
bool TelnetProxy::init()
{
if (0 != uv_loop_init(&m_loop))
return false;
if (0 != uv_async_init(&m_loop, &m_clean_session_handle, _on_clean_session_cb))
return false;
m_clean_session_handle.data = this;
m_host_ip = g_telnet_env.bind_ip;
m_host_port = g_telnet_env.bind_port;
if (0 != uv_tcp_init(&m_loop, &m_handle))
return false;
m_handle.data = this;
return true;
}
void TelnetProxy::timer() {
// timer() will be called per one second, and I will do my job per 5 seconds.
m_timer_counter++;
if (m_timer_counter < 5)
return;
m_timer_counter = 0;
ExThreadSmartLock locker(m_lock);
ts_telnet_sessions::iterator it = m_sessions.begin();
for (; it != m_sessions.end(); ++it)
{
it->first->save_record();
}
}
void TelnetProxy::_thread_loop(void)
{
struct sockaddr_in addr;
if (0 != uv_ip4_addr(m_host_ip.c_str(), m_host_port, &addr)) {
EXLOGE("[telnet] invalid ip/port for TELNET listener.\n");
return;
}
if (0 != uv_tcp_bind(&m_handle, (const struct sockaddr*) &addr, 0)) {
EXLOGE("[telnet] can not bind %s:%d.\n", m_host_ip.c_str(), m_host_port);
return;
}
// 开始监听,有客户端连接到来时,会回调 _on_client_connect()
if (0 != uv_listen((uv_stream_t*)&m_handle, 8, _on_client_connect)) {
EXLOGE("[telnet] can not listen on %s:%d.\n", m_host_ip.c_str(), m_host_port);
return;
}
EXLOGI("[telnet] TeleportServer-TELNET ready on %s:%d\n", m_host_ip.c_str(), m_host_port);
int err = 0;
if ((err = uv_run(&m_loop, UV_RUN_DEFAULT)) != 0) {
EXLOGE("[telnet] main-loop end. %s\n", uv_strerror(err));
}
// 注意,如果在 uv_loop_close() 内部崩溃可能某个uv的handle未关闭。
uv_loop_close(&m_loop);
EXLOGV("[telnet] main-loop end.\n");
}
void TelnetProxy::_set_stop_flag(void) {
m_stop_flag = true;
if (m_is_running) {
uv_close((uv_handle_t*)&m_handle, _on_listener_closed);
}
}
// static
void TelnetProxy::_on_listener_closed(uv_handle_t* handle)
{
TelnetProxy* _this = (TelnetProxy*)handle->data;
EXLOGV("[telnet] listener close.\n");
_this->_close_all_sessions();
}
void TelnetProxy::clean_session() {
uv_async_send(&m_clean_session_handle);
}
void TelnetProxy::_close_all_sessions(void)
{
ExThreadSmartLock locker(m_lock);
if (m_sessions.size() == 0) {
_close_clean_session_handle();
return;
}
ts_telnet_sessions::iterator it = m_sessions.begin();
for (; it != m_sessions.end(); ++it)
{
it->first->close(TP_SESS_STAT_ERR_RESET);
}
}
// static
void TelnetProxy::_on_clean_session_cb(uv_async_t* handle)
{
TelnetProxy* _this = (TelnetProxy*)handle->data;
// check closed session
ExThreadSmartLock locker(_this->m_lock);
ts_telnet_sessions::iterator it = _this->m_sessions.begin();
for (; it != _this->m_sessions.end(); )
{
if (it->first->is_closed()) {
delete it->first;
_this->m_sessions.erase(it++);
EXLOGD("[telnet] - removed one session.\n");
}
else {
it++;
}
}
if (_this->m_stop_flag && _this->m_sessions.size() == 0) {
_this->_close_clean_session_handle();
}
}
//static
void TelnetProxy::_on_clean_session_handle_closed(uv_handle_t *handle) {
}
// static
void TelnetProxy::_on_client_connect(uv_stream_t* server, int status)
{
if (0 != status)
return;
TelnetProxy* _this = (TelnetProxy*)server->data;
_this->_on_accept(server);
}
bool TelnetProxy::_on_accept(uv_stream_t* server)
{
TelnetSession* sess = new TelnetSession(this);
if (0 != uv_accept(server, sess->client()->stream_handle()))
{
EXLOGE("[telnet] socket accept failed.\n");
delete sess;
return false;
}
if (m_stop_flag)
{
delete sess;
return false;
}
// 获取客户端IP地址和端口号
struct sockaddr sock_client;
int namelen = sizeof(sock_client);
if (0 == uv_tcp_getpeername(sess->client()->tcp_handle(), &sock_client, &namelen))
{
sockaddr_in* addrin = (sockaddr_in*)&sock_client;
char ip[17] = { 0 };
if (0 == uv_ip4_name(addrin, ip, sizeof(ip)))
{
char client_addr[64] = { 0 };
snprintf(client_addr, 64, "%s:%d", ip, addrin->sin_port);
sess->client_addr(client_addr);
}
}
EXLOGV("\n=================== NEW TELNET CLIENT [%s] ============\n", sess->client_addr());
{
ExThreadSmartLock locker(m_lock);
m_sessions.insert(std::make_pair(sess, 0));
}
sess->client()->start_recv();
return true;
}
void TelnetProxy::_close_clean_session_handle() {
uv_close((uv_handle_t*)&m_clean_session_handle, _on_clean_session_handle_closed);
}

View File

@ -0,0 +1,55 @@
#ifndef __TELNET_PROXY_H__
#define __TELNET_PROXY_H__
#include <uv.h>
#include <ex.h>
#include "telnet_session.h"
typedef std::map<TelnetSession*, unsigned char> ts_telnet_sessions;
class TelnetProxy : public ExThreadBase
{
public:
TelnetProxy();
~TelnetProxy();
bool init();
void timer();
uv_loop_t* get_loop() { return &m_loop; }
void clean_session();
protected:
void _thread_loop();
void _set_stop_flag();
void _close_all_sessions();
void _close_clean_session_handle();
private:
static void _on_client_connect(uv_stream_t* server, int status);
static void _on_listener_closed(uv_handle_t* handle);
static void _on_clean_session_cb(uv_async_t* handle);
static void _on_clean_session_handle_closed(uv_handle_t *handle);
bool _on_accept(uv_stream_t* server);
private:
bool m_stop_flag;
int m_timer_counter;
uv_loop_t m_loop;
uv_tcp_t m_handle;
uv_async_t m_clean_session_handle;
ExThreadLock m_lock;
ex_astr m_host_ip;
int m_host_port;
ts_telnet_sessions m_sessions;
};
extern TelnetProxy g_telnet_proxy;
#endif // __TELNET_PROXY_H__

View File

@ -0,0 +1,191 @@
#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();
}
bool TppTelnetRec::_save_to_cmd_file()
{
if (m_cmd_cache.size() == 0)
return true;
if (NULL == m_file_cmd) {
ex_wstr fname = m_base_path;
ex_path_join(fname, false, m_base_fname.c_str(), NULL);
fname += L"-cmd.txt";
m_file_cmd = ex_fopen(fname, L"wb");
if (NULL == m_file_cmd)
{
EXLOGE("[ssh] can not open record cmd-file for write.\n");
return false;
}
m_header_changed = true;
}
fwrite(m_cmd_cache.data(), m_cmd_cache.size(), 1, m_file_cmd);
fflush(m_file_cmd);
m_cmd_cache.empty();
return _save_to_info_file();
}

View File

@ -0,0 +1,53 @@
#ifndef __TELNET_RECORDER_H__
#define __TELNET_RECORDER_H__
#include "../../common/base_record.h"
#define TS_RECORD_TYPE_TELNET_TERM_SIZE 0x01 // 终端大小(行数与列数)
#define TS_RECORD_TYPE_TELNET_DATA 0x02 // 用于展示的数据内容
#pragma pack(push,1)
// 记录窗口大小改变的数据包
typedef struct TS_RECORD_WIN_SIZE
{
ex_u16 width;
ex_u16 height;
}TS_RECORD_WIN_SIZE;
#pragma pack(pop)
class TppTelnetRec : public TppRecBase
{
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);
void save_record();
protected:
bool _on_begin(const TPP_CONNECT_INFO* info);
bool _on_end();
bool _save_to_info_file();
bool _save_to_data_file();
bool _save_to_cmd_file();
protected:
TS_RECORD_HEADER m_head;
bool m_header_changed;
MemBuffer m_cmd_cache;
bool m_save_full_header;
FILE* m_file_info;
FILE* m_file_data;
FILE* m_file_cmd;
};
#endif // __TELNET_RECORDER_H__

View File

@ -0,0 +1,742 @@
#include "telnet_session.h"
#include "telnet_proxy.h"
#include "tpp_env.h"
#include <teleport_const.h>
#define TELNET_IAC 255
#define TELNET_DONT 254
#define TELNET_DO 253
#define TELNET_WONT 252
#define TELNET_WILL 251
#define TELNET_SB 250
#define TELNET_SE 240
TelnetSession::TelnetSession(TelnetProxy *proxy) :
m_proxy(proxy),
m_conn_info(NULL)
{
m_client_type = 0;
m_state = TP_SESS_STAT_RUNNING;
m_db_id = 0;
m_is_relay = false;
m_is_closed = false;
m_is_putty_mode = false;
m_is_putty_eat_username = false;
m_username_sent = false;
m_password_sent = false;
m_conn_server = new TelnetConn(this, false);
m_conn_client = new TelnetConn(this, true);
m_status = s_client_connect;
m_client_addr = "unknown-ip";
}
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);
}
EXLOGD("[telnet] session destroy.\n");
}
void TelnetSession::save_record() {
m_rec.save_record();
}
void TelnetSession::_session_error(int err_code) {
int db_id = 0;
if (!g_telnet_env.session_begin(m_conn_info, &db_id) || db_id == 0)
{
EXLOGE("[telnet] can not write session error to database.\n");
return;
}
g_telnet_env.session_end(m_sid.c_str(), db_id, err_code);
}
bool TelnetSession::_on_session_begin() {
if (!g_telnet_env.session_begin(m_conn_info, &m_db_id)) {
EXLOGE("[telnet] can not save to database, session begin failed.\n");
return false;
}
if (!g_telnet_env.session_update(m_db_id, m_conn_info->protocol_sub_type, TP_SESS_STAT_STARTED)) {
EXLOGE("[telnet] can not update state, session begin failed.\n");
return false;
}
m_rec.begin(g_telnet_env.replay_path.c_str(), L"tp-telnet", m_db_id, m_conn_info);
return true;
}
bool TelnetSession::_on_session_end()
{
if (m_db_id > 0)
{
// 如果会话过程中没有发生错误,则将其状态改为结束,否则记录下错误值
if (m_state == TP_SESS_STAT_RUNNING || m_state == TP_SESS_STAT_STARTED)
m_state = TP_SESS_STAT_END;
EXLOGD("[telnet] session end with code: %d\n", m_state);
g_telnet_env.session_end(m_sid.c_str(), m_db_id, m_state);
}
return true;
}
uv_loop_t *TelnetSession::get_loop(void) {
return m_proxy->get_loop();
}
void TelnetSession::close(int err_code) {
_do_close(err_code);
}
void TelnetSession::do_next(TelnetConn *conn, sess_state status) {
if (m_status < s_close)
m_status = status;
do_next(conn);
}
void TelnetSession::do_next(TelnetConn *conn) {
sess_state new_status;
ASSERT(m_status != s_dead);
switch (m_status) {
case s_noop:
return;
case s_client_connect:
new_status = _do_client_connect(conn);
break;
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;
case s_close:
new_status = _do_close(m_state);
break;
case s_closing:
new_status = _do_check_closing();
break;
case s_all_conn_closed:
new_status = s_dead;
break;
default:
//UNREACHABLE();
return;
}
m_status = new_status;
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();
}
}
/*
session
1. TelnetConnsession on_conn_closed();
2. session->on_conn_closed()connsession.
*/
sess_state TelnetSession::_do_close(int state) {
EXLOGD("[telnet] _do_close(). m_status=%d\n", m_status);
if (m_status >= s_close)
return m_status;
if (state == TP_SESS_STAT_END) {
if (!m_is_relay)
m_state = TP_SESS_STAT_ERR_INTERNAL;
else
m_state = state;
}
else {
if (!m_is_relay)
_session_error(state);
m_state = state;
}
EXLOGV("[telnet] close session.\n");
EXLOGD("[telnet] _do_close(), conn_client::state=%d, conn_server:state=%d\n", m_conn_client->state(), m_conn_server->state());
m_conn_client->close();
m_conn_server->close();
m_status = s_closing;
return m_status;
}
sess_state TelnetSession::_do_check_closing() {
if (m_conn_client->state() == TELNET_CONN_STATE_FREE && m_conn_server->state() == TELNET_CONN_STATE_FREE)
return s_all_conn_closed;
else
return s_closing;
}
void TelnetSession::on_conn_close() {
EXLOGD("[telnet] on_conn_close(), conn_client::state=%d, conn_server:state=%d\n", m_conn_client->state(), m_conn_server->state());
if (m_conn_client->state() == TELNET_CONN_STATE_FREE && m_conn_server->state() == TELNET_CONN_STATE_FREE) {
m_status = s_all_conn_closed;
do_next(m_conn_client);
}
}
sess_state TelnetSession::_do_client_connect(TelnetConn* conn) {
// putty会率先发第一个包SecureCRT会通过脚本发第一个包
return _do_negotiation_with_client(conn);
}
sess_state TelnetSession::_do_negotiation_with_client(TelnetConn* conn) {
if (NULL == conn)
return s_negotiation_with_client;
if (0 == conn->data().size())
return s_negotiation_with_client;
MemBuffer mbuf_msg;
mbuf_msg.reserve(128);
MemStream ms_msg(mbuf_msg);
MemBuffer mbuf_resp;
mbuf_resp.reserve(conn->data().size());
MemStream ms_resp(mbuf_resp);
MemBuffer mbuf_sub;
mbuf_sub.reserve(128);
MemStream ms_sub(mbuf_sub);
MemStream s(conn->data());
ex_u8 ch = 0;
ex_u8 ch_cmd = 0;
for (; s.left() > 0;)
{
ch = s.get_u8();
if (ch == TELNET_IAC)
{
if (s.left() < 2)
return _do_close(TP_SESS_STAT_ERR_BAD_PKG);
if (mbuf_sub.size() > 0)
{
// 已经得到一个sub negotiation在处理新的数据前先处理掉旧的
ms_sub.reset();
}
ch_cmd = s.get_u8();
if (ch_cmd == TELNET_SB)
{
// SUB NEGOTIATION变长数据以 FF F0 结束
bool have_SE = false;
ex_u8 ch_sub = 0;
for (; s.left() > 0;)
{
ch_sub = s.get_u8();
if (ch_sub == TELNET_IAC)
{
if (s.left() > 0)
{
if (s.get_u8() == TELNET_SE)
{
have_SE = true;
break;
}
else
return _do_close(TP_SESS_STAT_ERR_BAD_PKG);
}
}
else
{
ms_sub.put_u8(ch_sub);
}
}
if (!have_SE)
return _do_close(TP_SESS_STAT_ERR_BAD_PKG);
}
else if (ch_cmd == TELNET_DONT)
{
ms_resp.put_u8(TELNET_IAC);
ms_resp.put_u8(TELNET_WONT);
ms_resp.put_u8(s.get_u8());
}
else if (ch_cmd == TELNET_DO)
{
ms_resp.put_u8(TELNET_IAC);
ms_resp.put_u8(TELNET_WILL);
ms_resp.put_u8(s.get_u8());
}
else if (ch_cmd == TELNET_WONT)
{
ms_resp.put_u8(TELNET_IAC);
ms_resp.put_u8(TELNET_DONT);
ms_resp.put_u8(s.get_u8());
}
else if (ch_cmd == TELNET_WILL)
{
ms_resp.put_u8(TELNET_IAC);
ms_resp.put_u8(TELNET_DO);
ms_resp.put_u8(s.get_u8());
}
else
{
s.skip(1);
}
}
else
{
ms_msg.put_u8(ch);
}
}
conn->data().empty();
if (mbuf_resp.size() > 0)
{
conn->send(mbuf_resp.data(), mbuf_resp.size());
}
if (mbuf_sub.size() == 5)
{
if (0 == memcmp(mbuf_sub.data(), "\x1f\x00\x50\x00\x18", 5))
{
m_is_putty_mode = true;
// ts_u8 _d[] = {
// 0xff, 0xfe, 0x20, 0xff, 0xfd, 0x18, 0xff, 0xfa, 0x27, 0x01, 0xff, 0xf0, 0xff, 0xfa, 0x27, 0x01,
// 0x03, 0x53, 0x46, 0x55, 0x54, 0x4c, 0x4e, 0x54, 0x56, 0x45, 0x52, 0x03, 0x53, 0x46, 0x55, 0x54,
// 0x4c, 0x4e, 0x54, 0x4d, 0x4f, 0x44, 0x45, 0xff, 0xf0, 0xff, 0xfd, 0x03
// };
ex_u8 _d[] = {
0xff, 0xfa, 0x27, 0x01,
0x03, 0x53, 0x46, 0x55, 0x54, 0x4c, 0x4e, 0x54, 0x56, 0x45, 0x52, 0x03, 0x53, 0x46, 0x55, 0x54,
0x4c, 0x4e, 0x54, 0x4d, 0x4f, 0x44, 0x45, 0xff, 0xf0
};
m_conn_client->send((ex_u8*)_d, sizeof(_d));
}
}
else if (mbuf_sub.size() > 8)
{
// 可能含有putty的登录用户名信息就是SID啦
if (0 == memcmp(mbuf_sub.data(), "\x27\x00\x00\x55\x53\x45\x52\x01", 8)) // '..USER.
{
mbuf_sub.pop(8);
for (; mbuf_sub.size() > 0;)
{
if (mbuf_sub.data()[mbuf_sub.size() - 1] == 0x0a || mbuf_sub.data()[mbuf_sub.size() - 1] == 0x0d)
mbuf_sub.size(mbuf_sub.size() - 1);
else
break;
}
mbuf_sub.append((ex_u8*)"\x00", 1);
m_sid = (char*)mbuf_sub.data();
}
}
if (mbuf_msg.size() > 0)
{
if (0 == memcmp(mbuf_msg.data(), "session:", 8))
{
mbuf_msg.pop(8);
for (; mbuf_msg.size() > 0;)
{
if (mbuf_msg.data()[mbuf_msg.size() - 1] == 0x0a || mbuf_msg.data()[mbuf_msg.size() - 1] == 0x0d)
mbuf_msg.size(mbuf_msg.size() - 1);
else
break;
}
mbuf_msg.append((ex_u8*)"\x00", 1);
m_sid = (char*)mbuf_msg.data();
}
}
if (m_sid.length() > 0)
{
EXLOGW("[telnet] session-id: %s\n", m_sid.c_str());
m_conn_info = g_telnet_env.get_connect_info(m_sid.c_str());
if (NULL == m_conn_info) {
EXLOGE("[telnet] no such session: %s\n", m_sid.c_str());
return _do_close(TP_SESS_STAT_ERR_SESSION);
}
else {
m_conn_ip = m_conn_info->conn_ip;
m_conn_port = m_conn_info->conn_port;
m_acc_name = m_conn_info->acc_username;
m_acc_secret = m_conn_info->acc_secret;
m_username_prompt = m_conn_info->username_prompt;
m_password_prompt = m_conn_info->password_prompt;
if (m_conn_info->protocol_type != TP_PROTOCOL_TYPE_TELNET) {
EXLOGE("[telnet] session '%s' is not for TELNET.\n", m_sid.c_str());
return _do_close(TP_SESS_STAT_ERR_SESSION);
}
}
// 记录日志,会话开始了
// set_info(sess_info);
// try to connect to real server.
m_conn_server->connect(m_conn_ip.c_str(), m_conn_port);
ex_astr szmsg = "Connect to ";
szmsg += m_conn_ip;
szmsg += "\r\n";
m_conn_client->send((ex_u8*)szmsg.c_str(), szmsg.length());
return s_noop;
}
return s_negotiation_with_client;
}
sess_state TelnetSession::_do_server_connected() {
m_conn_client->data().empty();
m_conn_server->data().empty();
m_status = s_relay;
if (m_is_putty_mode)
{
ex_u8 _d[] = "\xff\xfb\x1f\xff\xfb\x20\xff\xfb\x18\xff\xfb\x27\xff\xfd\x01\xff\xfb\x03\xff\xfd\x03";
m_conn_server->send(_d, sizeof(_d) - 1);
}
EXLOGW("[telnet] enter relay mode.\n");
return s_relay;
}
sess_state TelnetSession::_do_relay(TelnetConn *conn) {
TelnetSession* _this = conn->session();
bool is_processed = false;
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))
{
_this->m_is_putty_eat_username = true;
_this->m_username_sent = true;
is_processed = true;
}
}
if (is_processed)
{
m_conn_client->data().empty();
return s_relay;
}
m_conn_server->send(m_conn_client->data().data(), m_conn_client->data().size());
m_conn_client->data().empty();
}
else
{
// 收到了服务端返回的数据
if (!_this->m_username_sent && _this->m_acc_name.length() > 0)
{
if (_this->_parse_find_and_send(m_conn_server, m_conn_client, _this->m_username_prompt.c_str(), _this->m_acc_name.c_str()))
{
_this->m_username_sent = true;
is_processed = true;
}
}
if (!_this->m_password_sent && _this->m_password_prompt.length() > 0)
{
if (_this->_parse_find_and_send(m_conn_server, m_conn_client, _this->m_password_prompt.c_str(), _this->m_acc_secret.c_str()))
{
_this->m_password_sent = true;
is_processed = true;
}
}
if (is_processed)
{
m_conn_server->data().empty();
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_server->data().empty();
}
return s_relay;
}
bool TelnetSession::_parse_find_and_send(TelnetConn* conn_recv, TelnetConn* conn_remote, const char* find, const char* send)
{
size_t find_len = strlen(find);
size_t send_len = strlen(send);
if (0 == find_len || 0 == send_len)
return false;
MemBuffer mbuf_msg;
mbuf_msg.reserve(128);
MemStream ms_msg(mbuf_msg);
MemStream s(conn_recv->data());
ex_u8 ch = 0;
ex_u8 ch_cmd = 0;
for (; s.left() > 0;)
{
ch = s.get_u8();
if (ch == TELNET_IAC)
{
if (s.left() < 2)
return false;
ch_cmd = s.get_u8();
if (ch_cmd == TELNET_SB)
{
// SUB NEGOTIATION变长数据以 FF F0 结束
bool have_SE = false;
ex_u8 ch_sub = 0;
for (; s.left() > 0;)
{
ch_sub = s.get_u8();
if (ch_sub == TELNET_IAC)
{
if (s.left() > 0)
{
if (s.get_u8() == TELNET_SE)
{
have_SE = true;
break;
}
else
return false;
}
}
}
if (!have_SE)
return false;
}
else
{
s.skip(1);
}
}
else
{
ms_msg.put_u8(ch);
}
}
if (mbuf_msg.size() < find_len)
return false;
int find_range = mbuf_msg.size() - find_len;
for (int i = 0; i < find_range; ++i)
{
if (0 == memcmp(mbuf_msg.data() + i, find, find_len))
{
conn_remote->send(conn_recv->data().data(), conn_recv->data().size());
conn_recv->data().empty();
mbuf_msg.empty();
mbuf_msg.append((ex_u8*)send, send_len);
mbuf_msg.append((ex_u8*)"\x0d\x0a", 2);
conn_recv->send(mbuf_msg.data(), mbuf_msg.size());
return true;
}
}
return false;
}
bool TelnetSession::_eat_username(TelnetConn* conn_recv, TelnetConn* conn_remote)
{
bool replaced = false;
MemBuffer mbuf_msg;
mbuf_msg.reserve(128);
MemStream ms_msg(mbuf_msg);
MemStream s(conn_recv->data());
ex_u8 ch = 0;
ex_u8 ch_cmd = 0;
for (; s.left() > 0;)
{
ch = s.get_u8();
if (ch == TELNET_IAC)
{
if (s.left() < 2)
return false;
ch_cmd = s.get_u8();
if (ch_cmd == TELNET_SB)
{
size_t _begin = s.offset();
size_t _end = 0;
// SUB NEGOTIATION变长数据以 FF F0 结束
bool have_SE = false;
ex_u8 ch_sub = 0;
for (; s.left() > 0;)
{
_end = s.offset();
ch_sub = s.get_u8();
if (ch_sub == TELNET_IAC)
{
if (s.left() > 0)
{
if (s.get_u8() == TELNET_SE)
{
have_SE = true;
break;
}
else
return false;
}
}
}
if (!have_SE)
return false;
size_t len = _end - _begin;
if (len <= 8 || 0 != memcmp("\x27\x00\x00\x55\x53\x45\x52\x01", conn_recv->data().data() + _begin, 8))
{
ms_msg.put_u8(TELNET_IAC);
ms_msg.put_u8(TELNET_SB);
ms_msg.put_bin(conn_recv->data().data() + _begin, len);
ms_msg.put_u8(TELNET_IAC);
ms_msg.put_u8(TELNET_SE);
continue;
}
// 到这里就找到了客户端发来的用户名,我们将其抛弃掉,发给服务端的是一个无用户名的包,这样
// 服务端就会提示输入用户名login:),后续检测到服务端的提示就会发送用户名了。
ms_msg.put_u8(TELNET_IAC);
ms_msg.put_u8(TELNET_SB);
ms_msg.put_bin((ex_u8*)"\x27\x00\x00\x55\x53\x45\x52\x01", 8);
ms_msg.put_bin((ex_u8*)m_acc_name.c_str(), m_acc_name.length());
ms_msg.put_u8(TELNET_IAC);
ms_msg.put_u8(TELNET_SE);
replaced = true;
}
else
{
ms_msg.put_u8(ch);
ms_msg.put_u8(ch_cmd);
ms_msg.put_u8(s.get_u8());
}
}
else
{
ms_msg.put_u8(ch);
}
}
if (replaced)
{
conn_remote->send(mbuf_msg.data(), mbuf_msg.size());
return true;
}
return false;
}

View File

@ -0,0 +1,128 @@
#ifndef __TELNET_SESSION_H__
#define __TELNET_SESSION_H__
#include <ex.h>
#include "telnet_recorder.h"
#include "telnet_conn.h"
enum sess_state {
s_noop, // 什么都不做,等特定状态满足
s_client_connect, // 客户端连接
s_negotiation_with_client, // 与客户端进行握手直到得到客户端发来的登录用户名其实是SessionID
// s_connect_server, // 与服务端连接
s_server_connected, // 成功连接上服务器了
s_relay, // 正常转发数据
s_close, // 关闭会话
s_closing, // 正在关闭双方连接
s_all_conn_closed, // 两端均已关闭
s_dead // 可以销毁此会话了
};
class TelnetProxy;
class TelnetSession
{
public:
TelnetSession(TelnetProxy* proxy);
virtual ~TelnetSession();
TelnetProxy* get_proxy() { return m_proxy; }
TelnetConn* client() { return m_conn_client; }
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();
void do_next(TelnetConn* conn);
void do_next(TelnetConn* conn, sess_state status);
// save record cache into file. be called per 5 seconds.
void save_record();
void record(ex_u8 type, const ex_u8* data, size_t size) {
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; }
protected:
// 继承自 TppSessionBase
bool _on_session_begin();
bool _on_session_end();
void _session_error(int err_code);
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;
int m_db_id;
bool m_is_relay; // 是否进入relay模式了只有进入relay模式才会有录像存在
bool m_is_closed;
TppTelnetRec m_rec;
TelnetProxy* m_proxy;
TelnetConn* m_conn_client; // 与真正客户端通讯的连接(自身作为服务端)
TelnetConn* m_conn_server; // 与真正服务端通讯的连接(自身作为客户端)
ExThreadLock m_lock;
ex_astr m_sid;
ex_astr m_conn_ip;
ex_u16 m_conn_port;
ex_astr m_acc_name;
ex_astr m_acc_secret;
ex_astr m_username_prompt;
ex_astr m_password_prompt;
sess_state m_status;
ex_astr m_client_addr;
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;
};
#endif // __TELNET_SESSION_H__

View File

@ -0,0 +1,33 @@
#include "tpp_env.h"
TppTelnetEnv g_telnet_env;
TppTelnetEnv::TppTelnetEnv()
{}
TppTelnetEnv::~TppTelnetEnv()
{}
bool TppTelnetEnv::_on_init(TPP_INIT_ARGS* args) {
ex_path_join(replay_path, false, L"telnet", NULL);
ExIniSection* ps = args->cfg->GetSection(L"protocol-telnet");
if (NULL == ps) {
EXLOGE("[telnet] invalid config(2).\n");
return false;
}
ex_wstr tmp;
if (!ps->GetStr(L"bind-ip", tmp)) {
bind_ip = TS_RDP_PROXY_HOST;
}
else {
ex_wstr2astr(tmp, bind_ip);
}
if (!ps->GetInt(L"bind-port", bind_port)) {
bind_port = TS_RDP_PROXY_PORT;
}
return true;
}

View File

@ -0,0 +1,22 @@
#ifndef __TPP_ENV_H__
#define __TPP_ENV_H__
#include "../../common/base_env.h"
class TppTelnetEnv : public TppEnvBase
{
public:
TppTelnetEnv();
~TppTelnetEnv();
public:
ex_astr bind_ip;
int bind_port;
private:
bool _on_init(TPP_INIT_ARGS* args);
};
extern TppTelnetEnv g_telnet_env;
#endif // __TPP_ENV_H__

View File

@ -0,0 +1,32 @@
#include "telnet_proxy.h"
#include "tpp_env.h"
#include <teleport_const.h>
TPP_API ex_rv tpp_init(TPP_INIT_ARGS* init_args)
{
if (!g_telnet_env.init(init_args))
return TPE_FAILED;
return 0;
}
TPP_API ex_rv tpp_start(void)
{
if (!g_telnet_proxy.init())
return TPE_FAILED;
if (!g_telnet_proxy.start())
return TPE_FAILED;
return 0;
}
TPP_API ex_rv tpp_stop(void)
{
g_telnet_proxy.stop();
return 0;
}
TPP_API void tpp_timer(void) {
// be called per one second.
g_telnet_proxy.timer();
}

View File

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tptelnet", "tptelnet.vs2015.vcxproj", "{FDA16D20-09B7-45AF-ADF1-DAF3EF2C0531}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FDA16D20-09B7-45AF-ADF1-DAF3EF2C0531}.Debug|x86.ActiveCfg = Debug|Win32
{FDA16D20-09B7-45AF-ADF1-DAF3EF2C0531}.Debug|x86.Build.0 = Debug|Win32
{FDA16D20-09B7-45AF-ADF1-DAF3EF2C0531}.Release|x86.ActiveCfg = Release|Win32
{FDA16D20-09B7-45AF-ADF1-DAF3EF2C0531}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,234 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{FDA16D20-09B7-45AF-ADF1-DAF3EF2C0531}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>tptelnet</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
<ProjectName>tptelnet</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140_xp</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>..\..\..\..\out\server\$(PlatformTarget)\$(Configuration)\</OutDir>
<IntDir>..\..\..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>..\..\..\..\out\server\$(PlatformTarget)\$(Configuration)\</OutDir>
<IntDir>..\..\..\..\out\_tmp_\$(ProjectName)\$(PlatformTarget)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;_DEBUG;_WINDOWS;_USRDLL;TPP_EXPORTS;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\..\common\teleport;..\..\..\..\common\libex\include;..\..\..\..\external\mbedtls\include;..\..\..\..\external\libuv\include;..\..\..\..\external\libuv\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<AdditionalLibraryDirectories>..\..\..\..\external\openssl\out32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>Debug</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;_CRT_SECURE_NO_WARNINGS;NDEBUG;_WINDOWS;_USRDLL;TPP_EXPORTS;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\..\common\teleport;..\..\..\..\common\libex\include;..\..\..\..\external\mbedtls\include;..\..\..\..\external\libuv\include;..\..\..\..\external\libuv\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>..\..\..\..\external\openssl\out32;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\..\..\common\libex\include\ex.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_const.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_ini.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_log.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_path.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_platform.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_str.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_thread.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_types.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_util.h" />
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_winsrv.h" />
<ClInclude Include="..\..\..\..\common\teleport\teleport_const.h" />
<ClInclude Include="..\..\..\..\external\libuv\include\tree.h" />
<ClInclude Include="..\..\..\..\external\libuv\include\uv-errno.h" />
<ClInclude Include="..\..\..\..\external\libuv\include\uv-threadpool.h" />
<ClInclude Include="..\..\..\..\external\libuv\include\uv-version.h" />
<ClInclude Include="..\..\..\..\external\libuv\include\uv-win.h" />
<ClInclude Include="..\..\..\..\external\libuv\include\uv.h" />
<ClInclude Include="..\..\..\..\external\libuv\src\heap-inl.h" />
<ClInclude Include="..\..\..\..\external\libuv\src\queue.h" />
<ClInclude Include="..\..\..\..\external\libuv\src\uv-common.h" />
<ClInclude Include="..\..\..\..\external\libuv\src\win\winapi.h" />
<ClInclude Include="..\..\..\..\external\libuv\src\win\winsock.h" />
<ClInclude Include="..\..\common\base_env.h" />
<ClInclude Include="..\..\common\base_record.h" />
<ClInclude Include="..\..\common\protocol_interface.h" />
<ClInclude Include="..\..\common\ts_const.h" />
<ClInclude Include="..\..\common\ts_membuf.h" />
<ClInclude Include="..\..\common\ts_memstream.h" />
<ClInclude Include="telnet_conn.h" />
<ClInclude Include="telnet_proxy.h" />
<ClInclude Include="telnet_recorder.h" />
<ClInclude Include="telnet_session.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="tpp_env.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\..\common\libex\src\ex_ini.cpp" />
<ClCompile Include="..\..\..\..\common\libex\src\ex_log.cpp" />
<ClCompile Include="..\..\..\..\common\libex\src\ex_path.cpp" />
<ClCompile Include="..\..\..\..\common\libex\src\ex_str.cpp" />
<ClCompile Include="..\..\..\..\common\libex\src\ex_thread.cpp" />
<ClCompile Include="..\..\..\..\common\libex\src\ex_util.cpp" />
<ClCompile Include="..\..\..\..\common\libex\src\ex_winsrv.cpp" />
<ClCompile Include="..\..\..\..\external\libuv\src\fs-poll.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\inet.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\threadpool.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\uv-common.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\version.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\async.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\core.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\detect-wakeup.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\dl.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\error.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\fs-event.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\fs.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\getaddrinfo.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\getnameinfo.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\handle.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\loop-watcher.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\pipe.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\poll.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\process-stdio.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\process.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\req.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\signal.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\snprintf.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\stream.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\tcp.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\thread.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\timer.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\tty.c" />
<ClCompile Include="..\..\..\..\external\libuv\src\win\udp.c" />
<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" />
<ClCompile Include="..\..\common\ts_memstream.cpp" />
<ClCompile Include="dllmain.cpp">
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader>
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader>
</ClCompile>
<ClCompile Include="telnet_conn.cpp" />
<ClCompile Include="telnet_proxy.cpp" />
<ClCompile Include="telnet_recorder.cpp" />
<ClCompile Include="telnet_session.cpp" />
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="tpp_env.cpp" />
<ClCompile Include="tptelnet.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,422 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="common">
<UniqueIdentifier>{73f964a0-2430-47c6-b083-956809018ec2}</UniqueIdentifier>
</Filter>
<Filter Include="libex">
<UniqueIdentifier>{68aa1482-4f0d-43b5-9bbd-d7857e9b540b}</UniqueIdentifier>
</Filter>
<Filter Include="libex\header">
<UniqueIdentifier>{e6941d07-304a-4ba8-af5a-c5a09dae61b4}</UniqueIdentifier>
</Filter>
<Filter Include="libex\src">
<UniqueIdentifier>{4a7ed97e-93c1-4513-b813-3399eaeb8a2f}</UniqueIdentifier>
</Filter>
<Filter Include="win32">
<UniqueIdentifier>{b95409eb-4905-440f-8537-ee892e96b49a}</UniqueIdentifier>
</Filter>
<Filter Include="main app">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="libuv">
<UniqueIdentifier>{c33b46b3-8d5d-4dff-851b-4a9394b198d0}</UniqueIdentifier>
</Filter>
<Filter Include="libuv\header">
<UniqueIdentifier>{e3918a55-cbc1-4d69-bed8-c0146f2f4ce2}</UniqueIdentifier>
</Filter>
<Filter Include="libuv\src">
<UniqueIdentifier>{c248e06b-21a4-4f6d-b0ca-0f1b2a5783bd}</UniqueIdentifier>
</Filter>
<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">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_ini.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_log.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_path.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_platform.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_str.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_thread.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_types.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_util.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex\ex_winsrv.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\libex\include\ex.h">
<Filter>libex\header</Filter>
</ClInclude>
<ClInclude Include="stdafx.h">
<Filter>win32</Filter>
</ClInclude>
<ClInclude Include="targetver.h">
<Filter>win32</Filter>
</ClInclude>
<ClInclude Include="telnet_proxy.h">
<Filter>main app</Filter>
</ClInclude>
<ClInclude Include="telnet_session.h">
<Filter>main app</Filter>
</ClInclude>
<ClInclude Include="..\..\common\ts_const.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\common\protocol_interface.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\common\base_record.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\common\ts_membuf.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="tpp_env.h">
<Filter>main app</Filter>
</ClInclude>
<ClInclude Include="..\..\common\base_env.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="telnet_recorder.h">
<Filter>main app</Filter>
</ClInclude>
<ClInclude Include="telnet_conn.h">
<Filter>main app</Filter>
</ClInclude>
<ClInclude Include="..\..\common\ts_memstream.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\include\tree.h">
<Filter>libuv\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\include\uv.h">
<Filter>libuv\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\include\uv-errno.h">
<Filter>libuv\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\include\uv-threadpool.h">
<Filter>libuv\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\include\uv-version.h">
<Filter>libuv\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\include\uv-win.h">
<Filter>libuv\header</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\src\heap-inl.h">
<Filter>libuv\src</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\src\queue.h">
<Filter>libuv\src</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\src\uv-common.h">
<Filter>libuv\src</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\src\win\winapi.h">
<Filter>libuv\src\win</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\external\libuv\src\win\winsock.h">
<Filter>libuv\src\win</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\common\teleport\teleport_const.h">
<Filter>common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="tptelnet.cpp">
<Filter>main app</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\common\libex\src\ex_ini.cpp">
<Filter>libex\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\common\libex\src\ex_log.cpp">
<Filter>libex\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\common\libex\src\ex_path.cpp">
<Filter>libex\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\common\libex\src\ex_str.cpp">
<Filter>libex\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\common\libex\src\ex_thread.cpp">
<Filter>libex\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\common\libex\src\ex_util.cpp">
<Filter>libex\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\common\libex\src\ex_winsrv.cpp">
<Filter>libex\src</Filter>
</ClCompile>
<ClCompile Include="dllmain.cpp">
<Filter>win32</Filter>
</ClCompile>
<ClCompile Include="stdafx.cpp">
<Filter>win32</Filter>
</ClCompile>
<ClCompile Include="telnet_proxy.cpp">
<Filter>main app</Filter>
</ClCompile>
<ClCompile Include="telnet_session.cpp">
<Filter>main app</Filter>
</ClCompile>
<ClCompile Include="..\..\common\base_record.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\common\ts_membuf.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="tpp_env.cpp">
<Filter>main app</Filter>
</ClCompile>
<ClCompile Include="..\..\common\base_env.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="telnet_recorder.cpp">
<Filter>main app</Filter>
</ClCompile>
<ClCompile Include="telnet_conn.cpp">
<Filter>main app</Filter>
</ClCompile>
<ClCompile Include="..\..\common\ts_memstream.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\fs-poll.c">
<Filter>libuv\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\inet.c">
<Filter>libuv\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\threadpool.c">
<Filter>libuv\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\uv-common.c">
<Filter>libuv\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\version.c">
<Filter>libuv\src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\req.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\signal.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\snprintf.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\stream.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\tcp.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\thread.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\timer.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\tty.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\udp.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\util.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\winapi.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\winsock.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\async.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\core.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\detect-wakeup.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\dl.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\error.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\fs.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\fs-event.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\getaddrinfo.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\getnameinfo.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\handle.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\loop-watcher.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\pipe.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\poll.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\external\libuv\src\win\process.c">
<Filter>libuv\src\win</Filter>
</ClCompile>
<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

@ -19,9 +19,9 @@ $app.on_init = function (cb_stack) {
upload_file_message: $('#upload-file-message')
};
$tp.assist_checked = function() {
$tp.assist_checked = function () {
console.log("---------");
if($tp.assist.running) {
if ($tp.assist.running) {
$app.dom.assist_ver.html($tp.assist.version);
} else {
$app.dom.assist_ver.html('<a href="http://teleport.eomsoft.net/download" target="_blank" class="error">未能检测到</a>');
@ -1380,6 +1380,8 @@ $app.create_dlg_edit_account = function () {
dlg.field_username = '';
dlg.field_password = '';
dlg.field_pri_key = '';
dlg.field_prompt_username = '';
dlg.field_prompt_password = '';
dlg.protocol_sub_type = 0;
dlg.dom = {
@ -1475,7 +1477,7 @@ $app.create_dlg_edit_account = function () {
html.push('<option value="1">用户名/密码 认证</option>');
if (dlg.host.router_ip.length === 0) {
if(_.isNull(dlg.account))
if (_.isNull(dlg.account))
dlg.dom.protocol_port.val(3389);
else
dlg.dom.protocol_port.val(dlg.account.protocol_port);
@ -1491,7 +1493,7 @@ $app.create_dlg_edit_account = function () {
html.push('<option value="2">SSH私钥 认证</option>');
if (dlg.host.router_ip.length === 0) {
if(_.isNull(dlg.account))
if (_.isNull(dlg.account))
dlg.dom.protocol_port.val(22);
else
dlg.dom.protocol_port.val(dlg.account.protocol_port);
@ -1507,10 +1509,16 @@ $app.create_dlg_edit_account = function () {
html.push('<option value="0">无需认证</option>');
if (dlg.host.router_ip.length === 0) {
if(_.isNull(dlg.account))
if (_.isNull(dlg.account)) {
dlg.dom.protocol_port.val(23);
else
dlg.dom.prompt_username.val('ogin:');
dlg.dom.prompt_password.val('assword:');
}
else {
dlg.dom.protocol_port.val(dlg.account.protocol_port);
dlg.dom.prompt_username.val(dlg.account.username_prompt);
dlg.dom.prompt_password.val(dlg.account.password_prompt);
}
}
dlg.protocol_sub_type = TP_PROTOCOL_TYPE_TELNET_SHELL;
@ -1527,12 +1535,20 @@ $app.create_dlg_edit_account = function () {
if (dlg.field_auth === TP_AUTH_TYPE_PASSWORD) {
dlg.dom.block_password.show();
dlg.dom.block_sshkey.hide();
if (dlg.field_protocol === TP_PROTOCOL_TYPE_TELNET) {
dlg.dom.block_prompt.show();
if(dlg.dom.prompt_username.val().length === 0 && dlg.account.username_prompt.length === 0)
dlg.dom.prompt_username.val('ogin:');
if(dlg.dom.prompt_password.val().length === 0 && dlg.account.password_prompt.length === 0)
dlg.dom.prompt_password.val('assword:');
}
} else if (dlg.field_auth === TP_AUTH_TYPE_PRIVATE_KEY) {
dlg.dom.block_password.hide();
dlg.dom.block_sshkey.show();
} else if (dlg.field_auth === TP_AUTH_TYPE_NONE) {
dlg.dom.block_password.hide();
dlg.dom.block_sshkey.hide();
dlg.dom.block_prompt.hide();
}
};
@ -1564,6 +1580,8 @@ $app.create_dlg_edit_account = function () {
dlg.field_username = dlg.dom.username.val();
dlg.field_password = dlg.dom.password.val();
dlg.field_pri_key = dlg.dom.ssh_prikey.val();
dlg.field_prompt_username = dlg.dom.prompt_username.val();
dlg.field_prompt_password = dlg.dom.prompt_password.val();
if (dlg.host.router_ip.length === 0) {
if (dlg.dom.protocol_port.val().length === 0) {
@ -1589,18 +1607,30 @@ $app.create_dlg_edit_account = function () {
return false;
}
if (dlg.field_protocol !== TP_PROTOCOL_TYPE_TELNET) {
dlg.field_prompt_username = '';
dlg.field_prompt_password = '';
}
if (dlg.field_auth_type === TP_AUTH_TYPE_PASSWORD) {
if (dlg.field_id === -1 && dlg.field_password.length === 0) {
dlg.dom.password.focus();
$tp.notify_error('请填写登录远程主机的密码!');
return false;
}
dlg.field_pri_key = '';
} else if (dlg.field_auth_type === TP_AUTH_TYPE_PRIVATE_KEY) {
if (dlg.field_id === -1 && dlg.field_pri_key.length === 0) {
dlg.dom.ssh_prikey.focus();
$tp.notify_error('请填写登录远程主机的SSH私钥');
return false;
}
dlg.field_password = '';
} else if (dlg.field_auth_type === TP_AUTH_TYPE_NONE) {
dlg.field_prompt_username = '';
dlg.field_prompt_password = '';
dlg.field_password = '';
dlg.field_pri_key = '';
}
return true;
@ -1625,7 +1655,9 @@ $app.create_dlg_edit_account = function () {
auth_type: dlg.field_auth_type,
username: dlg.field_username,
password: dlg.field_password,
pri_key: dlg.field_pri_key
pri_key: dlg.field_pri_key,
username_prompt: dlg.field_prompt_username,
password_prompt: dlg.field_prompt_password
}
},
function (ret) {
@ -1670,7 +1702,9 @@ $app.create_dlg_edit_account = function () {
auth_type: dlg.field_auth_type,
username: dlg.field_username,
password: dlg.field_password,
pri_key: dlg.field_pri_key
pri_key: dlg.field_pri_key,
username_prompt: dlg.field_prompt_username,
password_prompt: dlg.field_prompt_password
},
function () {
// func_success

View File

@ -121,7 +121,7 @@ $app.on_table_host_cell_created = function (tbl, row_id, col_key, cell_obj) {
} else if (action === 'ssh') {
$app.connect_remote(uni_id, acc_id, host_id, TP_PROTOCOL_TYPE_SSH, protocol_sub_type);
} else if (action === 'telnet') {
$tp.notify_error('尚未实现!');
$app.connect_remote(uni_id, acc_id, host_id, TP_PROTOCOL_TYPE_TELNET, TP_PROTOCOL_TYPE_TELNET_SHELL);
}
});
}
@ -240,7 +240,9 @@ $app.on_table_host_render_created = function (render) {
}
act_btn.push('</div>');
} else if (acc.protocol_type === TP_PROTOCOL_TYPE_TELNET) {
act_btn.push('<div class="btn-group btn-group-sm">');
act_btn.push('<button type="button" class="btn btn-warning" data-action="telnet" data-id="' + acc.uni_id + '" data-acc-id="' + acc.a_id + '" data-host-id="' + acc.h_id + '" data-sub-protocol="' + TP_PROTOCOL_TYPE_TELNET_SHELL + '"><i class="fa fa-keyboard-o fa-fw"></i> TELNET</button>');
act_btn.push('</div>');
}
}

View File

@ -267,7 +267,7 @@
<select id="account-protocol-type" class="form-control">
<option value="1">RDP</option>
<option value="2">SSH</option>
## <option value="3">TELNET</option>
<option value="3">TELNET</option>
</select>
</div>
</div>

View File

@ -221,6 +221,8 @@ class DoUpdateAccountHandler(TPBaseJsonHandler):
param['username'] = args['param']['username'].strip()
param['password'] = args['param']['password']
param['pri_key'] = args['param']['pri_key'].strip()
param['username_prompt'] = args['param']['username_prompt'].strip()
param['password_prompt'] = args['param']['password_prompt'].strip()
except:
log.e('\n')
return self.write_json(TPE_PARAM)

View File

@ -167,6 +167,8 @@ class DoGetSessionIDHandler(TPBaseJsonHandler):
password = args['password']
pri_key = args['pri_key']
protocol_port = int(args['protocol_port'])
username_prompt = args['username_prompt']
password_prompt = args['password_prompt']
except:
return self.write_json(TPE_PARAM)
@ -183,6 +185,9 @@ class DoGetSessionIDHandler(TPBaseJsonHandler):
acc_info['password'] = password
acc_info['pri_key'] = pri_key
acc_info['username_prompt'] = username_prompt
acc_info['password_prompt'] = password_prompt
conn_info['_enc'] = 0
if acc_id == -1:
@ -219,8 +224,8 @@ class DoGetSessionIDHandler(TPBaseJsonHandler):
conn_info['acc_id'] = acc_id
conn_info['acc_username'] = acc_info['username']
conn_info['username_prompt'] = ''
conn_info['password_prompt'] = ''
conn_info['username_prompt'] = acc_info['username_prompt']
conn_info['password_prompt'] = acc_info['password_prompt']
conn_info['protocol_flag'] = 1
conn_info['protocol_type'] = acc_info['protocol_type']
@ -231,13 +236,15 @@ class DoGetSessionIDHandler(TPBaseJsonHandler):
conn_info['acc_secret'] = acc_info['password']
elif acc_info['auth_type'] == TP_AUTH_TYPE_PRIVATE_KEY:
conn_info['acc_secret'] = acc_info['pri_key']
else:
conn_info['acc_secret'] = ''
with tmp_conn_id_lock:
global tmp_conn_id_base
tmp_conn_id_base += 1
conn_id = tmp_conn_id_base
# log.v(conn_info)
log.v('CONN-INFO:', conn_info)
tp_session().set('tmp-conn-info-{}'.format(conn_id), conn_info, 10)
req = {'method': 'request_session', 'param': {'conn_id': conn_id}}

View File

@ -11,7 +11,7 @@ from app.base.stats import tp_stats
def get_account_info(acc_id):
s = SQL(get_db())
# s.select_from('acc', ['id', 'password', 'pri_key', 'state', 'host_ip', 'router_ip', 'router_port', 'protocol_type', 'protocol_port', 'auth_type', 'username'], alt_name='a')
s.select_from('acc', ['id', 'password', 'pri_key', 'state', 'host_id', 'protocol_type', 'protocol_port', 'auth_type', 'username'], alt_name='a')
s.select_from('acc', ['id', 'password', 'pri_key', 'state', 'host_id', 'protocol_type', 'protocol_port', 'auth_type', 'username', 'username_prompt', 'password_prompt'], alt_name='a')
s.where('a.id={}'.format(acc_id))
err = s.query()
if err != TPE_OK:
@ -37,7 +37,7 @@ def get_host_accounts(host_id):
# 获取指定主机的所有账号
s = SQL(get_db())
# s.select_from('acc', ['id', 'state', 'host_ip', 'router_ip', 'router_port', 'protocol_type', 'protocol_port', 'auth_type', 'username', 'pri_key'], alt_name='a')
s.select_from('acc', ['id', 'state', 'protocol_type', 'protocol_port', 'auth_type', 'username', 'pri_key'], alt_name='a')
s.select_from('acc', ['id', 'state', 'protocol_type', 'protocol_port', 'auth_type', 'username', 'username_prompt', 'password_prompt'], alt_name='a')
s.where('a.host_id={}'.format(host_id))
s.order_by('a.username', True)
@ -165,7 +165,7 @@ def get_accounts(sql_filter, sql_order, sql_limit, sql_restrict, sql_exclude):
s = SQL(db)
# s.select_from('acc', ['id', 'host_id', 'host_ip', 'router_ip', 'router_port', 'username', 'protocol_type', 'auth_type', 'state'], alt_name='a')
s.select_from('acc', ['id', 'host_id', 'username', 'protocol_type', 'auth_type', 'state'], alt_name='a')
s.select_from('acc', ['id', 'host_id', 'username', 'protocol_type', 'auth_type', 'state', 'username_prompt', 'password_prompt'], alt_name='a')
str_where = ''
_where = list()
@ -253,13 +253,13 @@ def add_account(handler, host_id, args):
if db_ret is not None and len(db_ret) > 0:
return TPE_EXISTS, 0
sql = 'INSERT INTO `{}acc` (host_id, host_ip, router_ip, router_port, protocol_type, protocol_port, state, auth_type, username, password, pri_key, creator_id, create_time) VALUES ' \
'({host_id}, "{host_ip}", "{router_ip}", {router_port}, {protocol_type}, {protocol_port}, {state}, {auth_type}, "{username}", "{password}", "{pri_key}", {creator_id}, {create_time});' \
sql = 'INSERT INTO `{}acc` (host_id, host_ip, router_ip, router_port, protocol_type, protocol_port, state, auth_type, username, username_prompt, password_prompt, password, pri_key, creator_id, create_time) VALUES ' \
'({host_id}, "{host_ip}", "{router_ip}", {router_port}, {protocol_type}, {protocol_port}, {state}, {auth_type}, "{username}", "{username_prompt}", "{password_prompt}", "{password}", "{pri_key}", {creator_id}, {create_time});' \
''.format(db.table_prefix,
host_id=host_id, host_ip=args['host_ip'], router_ip=args['router_ip'], router_port=args['router_port'],
protocol_type=args['protocol_type'], protocol_port=args['protocol_port'], state=TP_STATE_NORMAL,
auth_type=args['auth_type'], username=args['username'], password=args['password'], pri_key=args['pri_key'],
creator_id=operator['id'], create_time=_time_now)
auth_type=args['auth_type'], username=args['username'], username_prompt=args['username_prompt'], password_prompt=args['password_prompt'],
password=args['password'], pri_key=args['pri_key'], creator_id=operator['id'], create_time=_time_now)
# sql = 'INSERT INTO `{}acc` (host_id, protocol_type, protocol_port, state, auth_type, username, password, pri_key, creator_id, create_time) VALUES ' \
# '({host_id}, {protocol_type}, {protocol_port}, {state}, {auth_type}, "{username}", "{password}", "{pri_key}", {creator_id}, {create_time});' \
@ -311,6 +311,8 @@ def update_account(handler, host_id, acc_id, args):
_set.append('protocol_port={}'.format(args['protocol_port']))
_set.append('auth_type={}'.format(args['auth_type']))
_set.append('username="{}"'.format(args['username']))
_set.append('username_prompt="{}"'.format(args['username_prompt']))
_set.append('password_prompt="{}"'.format(args['password_prompt']))
if args['auth_type'] == TP_AUTH_TYPE_PASSWORD and len(args['password']) > 0:
_set.append('password="{}"'.format(args['password']))