├── README.md
├── packages.config
├── bio.h
├── debug_helper.h
├── shadow_client.h
├── LICENSE
├── debug_helper.cpp
├── shadow_tls.sln
├── shadow_tls_server.h
├── shadow_tls_client.h
├── bio.cpp
├── socket_select.h
├── shadow_tls.vcxproj.filters
├── socket_address.h
├── shadow_tls.cpp
├── autobuffer.h
├── shadow_tls_server.cpp
├── .gitignore
├── autobuffer.cpp
├── shadow_tls.vcxproj
├── shadow_tls_client.cpp
├── socket_select.cpp
├── shadow_client.cpp
└── socket_address.cpp
/README.md:
--------------------------------------------------------------------------------
1 | # shadow_tls
2 | shadow tls
3 |
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/bio.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 |
5 | enum ContextType
6 | {
7 | kContextServer,
8 | KContextClient
9 | };
10 |
11 | struct routine_context
12 | {
13 | ContextType type;
14 | SOCKET src_sock;
15 | SOCKET dst_sock;
16 | };
17 |
18 | int send_routine(void* ctx, const unsigned char* buf, size_t len);
19 | int recv_routine(void* ctx, unsigned char* buf, size_t len);
20 |
--------------------------------------------------------------------------------
/debug_helper.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | class debug_helper
4 | {
5 | public:
6 | static void debug(const char* file, int line, const char* format, ...);
7 | static void debug_w(const wchar_t* file, int line, const wchar_t* format, ...);
8 | };
9 |
10 | #define debug_log(x, ...) debug_helper::debug(__FILE__, __LINE__, x, ##__VA_ARGS__)
11 | #define debug_log_w(x, ...) debug_helper::debug_w(__FILEW__, __LINE__, x, ##__VA_ARGS__)
12 |
13 |
--------------------------------------------------------------------------------
/shadow_client.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | #include "socket_address.h"
6 | #include "socket_select.h"
7 |
8 | class AutoBuffer;
9 |
10 |
11 | class shadow_client
12 | {
13 | public:
14 | shadow_client();
15 | shadow_client(SOCKET remote_sock);
16 | ~shadow_client();
17 |
18 | SOCKET connect(const socket_address& _address, int& _errcode, int32_t _timeout = -1);
19 | int handshake();
20 | int send(const void* _buffer, size_t _len, int& _errcode, int _timeout = -1);
21 | int recv(SOCKET s, AutoBuffer& _buffer, size_t _max_size, int& _errcode, int _timeout = -1, bool _wait_full_size = false);
22 | void cancel();
23 |
24 | private:
25 | void init();
26 | int read_fix_size(SOCKET s, AutoBuffer& buffer, size_t size);
27 | SOCKET connect_impl(const socket_address& _address, int& _errcode, int32_t _timeout/*ms*/);
28 | int stream_data(SOCKET Source, SOCKET Dest);
29 |
30 | private:
31 | SOCKET socket_;
32 | SOCKET remote_socket_;
33 | SocketBreaker breaker_;
34 | };
35 |
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 puzz-h
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/debug_helper.cpp:
--------------------------------------------------------------------------------
1 | #include "debug_helper.h"
2 |
3 | #include
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #define LOG_MAXBUF_SIZE 2048
10 |
11 | void debug_helper::debug(const char* file, int line, const char* format, ...)
12 | {
13 | va_list va;
14 | va_start(va, format);
15 | const CHAR* pFileStr = nullptr;
16 | char szLogBuff[LOG_MAXBUF_SIZE] = { 0 };
17 | pFileStr = strrchr(file, '\\');
18 | pFileStr = (pFileStr == NULL) ? file : pFileStr + 1;
19 | int num_write = snprintf(szLogBuff, LOG_MAXBUF_SIZE - 1, "[%s:%d] ", pFileStr, line);
20 | vsnprintf(szLogBuff + num_write, LOG_MAXBUF_SIZE - num_write, format, va);
21 | OutputDebugStringA(szLogBuff);
22 | va_end(va);
23 | }
24 |
25 | void debug_helper::debug_w(const wchar_t* file, int line, const wchar_t* format, ...)
26 | {
27 | va_list va;
28 | va_start(va, format);
29 | const WCHAR* pFileStr = nullptr;
30 | WCHAR szLogBuff[LOG_MAXBUF_SIZE] = { 0 };
31 | pFileStr = wcsrchr(file, '\\');
32 | pFileStr = (pFileStr == NULL) ? file : pFileStr + 1;
33 | int num_write = swprintf_s(szLogBuff, LOG_MAXBUF_SIZE - 1, L"[%s:%d] ", pFileStr, line);
34 | vswprintf(szLogBuff + num_write, LOG_MAXBUF_SIZE - num_write, format, va);
35 | OutputDebugStringW(szLogBuff);
36 | va_end(va);
37 | }
38 |
--------------------------------------------------------------------------------
/shadow_tls.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.32901.82
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shadow_tls", "shadow_tls.vcxproj", "{5050C864-25E8-48FC-A846-4AF455287B29}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {5050C864-25E8-48FC-A846-4AF455287B29}.Debug|x64.ActiveCfg = Debug|x64
17 | {5050C864-25E8-48FC-A846-4AF455287B29}.Debug|x64.Build.0 = Debug|x64
18 | {5050C864-25E8-48FC-A846-4AF455287B29}.Debug|x86.ActiveCfg = Debug|Win32
19 | {5050C864-25E8-48FC-A846-4AF455287B29}.Debug|x86.Build.0 = Debug|Win32
20 | {5050C864-25E8-48FC-A846-4AF455287B29}.Release|x64.ActiveCfg = Release|x64
21 | {5050C864-25E8-48FC-A846-4AF455287B29}.Release|x64.Build.0 = Release|x64
22 | {5050C864-25E8-48FC-A846-4AF455287B29}.Release|x86.ActiveCfg = Release|Win32
23 | {5050C864-25E8-48FC-A846-4AF455287B29}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {02184C74-D95D-4A33-84BC-109D32654291}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/shadow_tls_server.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 |
5 | #include
6 | #include
7 |
8 | #include "socket_select.h"
9 |
10 | class shadow_tls_server;
11 |
12 | class MShadowServer
13 | {
14 | public:
15 | virtual ~MShadowServer(){}
16 | virtual void OnAccept(shadow_tls_server* server, SOCKET sock, const sockaddr_in& addr) = 0;
17 | virtual void OnError(shadow_tls_server* server, int err) = 0;
18 | };
19 |
20 | class shadow_tls_server
21 | {
22 | public:
23 | friend DWORD WINAPI thread_client(LPVOID lpThreadParameter);
24 | shadow_tls_server(MShadowServer& observer);
25 | shadow_tls_server(MShadowServer& observer, const std::string& shadow_domain);
26 | ~shadow_tls_server();
27 |
28 | int start_server(uint16_t port);
29 | void shutdown();
30 |
31 | int send(int id, const void* data, const int len);
32 |
33 | private:
34 | struct client_info
35 | {
36 | int id;
37 | SOCKET s;
38 | std::thread thread;
39 | bool handshaked;
40 | std::vector data;
41 |
42 | client_info()
43 | {
44 | handshaked = false;
45 | s = INVALID_SOCKET;
46 | id = -1;
47 | }
48 | };
49 |
50 | private:
51 | void init();
52 | void listen_routine();
53 | void client_routine(int id);
54 |
55 | private:
56 | std::string shadow_doamin_;
57 | SOCKET socket_listen_;
58 |
59 | SocketBreaker read_write_breaker_;
60 | bool shutdown_;
61 | std::thread listen_thread_;
62 | std::mutex client_mutex_;
63 | std::map clients_;
64 | MShadowServer& observer_;
65 | };
66 |
67 |
68 |
--------------------------------------------------------------------------------
/shadow_tls_client.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | class AutoBuffer;
16 |
17 | class MShadowEvent {
18 | public:
19 | virtual ~MShadowEvent() {}
20 |
21 | virtual void OnConnect() = 0;
22 | virtual void OnDisConnect(bool isremote) = 0;
23 | virtual void OnError(int errcode) = 0;
24 | };
25 |
26 | class shadow_tls_client
27 | {
28 | public:
29 | shadow_tls_client(MShadowEvent& event);
30 | ~shadow_tls_client();
31 |
32 | public:
33 | int connect(const std::string& server, const std::string& shadow_domain);
34 | void disconenct();
35 | void write(const void* buf, unsigned int len);
36 | SSIZE_T read(void* buf, unsigned int len);
37 |
38 | private:
39 | bool validate_address(const std::string& server);
40 | bool split_address_to_ip_and_port(const std::string& server, std::string& address, std::string& port);
41 | void io_thread();
42 |
43 | private:
44 | mbedtls_ctr_drbg_context ctr_drbg_;
45 | mbedtls_entropy_context entropy_;
46 |
47 | mbedtls_net_context net_ctx_;
48 | mbedtls_ssl_context ssl_ctx_;
49 | mbedtls_x509_crt ca_crt_;
50 | mbedtls_ssl_config ssl_conf_;
51 |
52 | std::mutex write_mutex_;
53 | std::mutex read_disconnect_mutex_;
54 | std::list lst_buffer_;
55 | std::list lst_rv_buffer_;
56 | std::thread thread_;
57 | bool will_disconnect_;
58 | MShadowEvent& event_;
59 | };
60 |
61 |
--------------------------------------------------------------------------------
/bio.cpp:
--------------------------------------------------------------------------------
1 | #include "bio.h"
2 |
3 | #include
4 |
5 | #include "shadow_client.h"
6 | #include "shadow_tls_server.h"
7 |
8 | enum RECORD_TYPE : unsigned char
9 | {
10 | recordTypeChangeCipherSpec = 20,
11 | recordTypeAlert = 21,
12 | recordTypeHandshake = 22,
13 | recordTypeApplicationData = 23,
14 | };
15 |
16 | enum RECORD_VERSION : unsigned short
17 | {
18 | VersionTLS10 = 0x0301,
19 | VersionTLS11 = 0x0302,
20 | VersionTLS12 = 0x0303,
21 | VersionTLS13 = 0x0304,
22 |
23 | VersionSSL30 = 0x0300
24 | };
25 |
26 | #pragma pack(push, 1)
27 | struct record_layer
28 | {
29 | RECORD_TYPE content_type;
30 | RECORD_VERSION version;
31 | unsigned short len;
32 | };
33 | #pragma pack(pop)
34 |
35 |
36 | int send_routine(void* ctx, const unsigned char* buf, size_t len)
37 | {
38 | assert(len >= 5);
39 | int send_len = 0;
40 | auto context = static_cast(ctx);
41 | auto record = reinterpret_cast(const_cast(buf));
42 | switch (context->type)
43 | {
44 | case kContextServer:
45 | send_len = ::send(context->dst_sock, (const char*)buf, len, 0);
46 | break;
47 | case KContextClient:
48 | send_len = ::send(context->dst_sock, (const char*)buf, len, 0);
49 | break;
50 | default: break;
51 | }
52 | return send_len;
53 | }
54 |
55 | int recv_routine(void* ctx, unsigned char* buf, size_t len)
56 | {
57 | assert(len >= 5);
58 | int recv_len = 0;
59 | auto context = static_cast(ctx);
60 | auto record = reinterpret_cast(buf);
61 | switch (context->type)
62 | {
63 | case kContextServer:
64 | recv_len = ::recv(context->dst_sock, (char*)buf, len, 0);
65 | break;
66 | case KContextClient:
67 | recv_len = ::recv(context->dst_sock, (char*)buf, len, 0);
68 | break;
69 | default: break;
70 | }
71 | return recv_len;
72 | }
73 |
--------------------------------------------------------------------------------
/socket_select.h:
--------------------------------------------------------------------------------
1 | #ifndef _SOCKSTSELECT_
2 | #define _SOCKSTSELECT_
3 |
4 | #include