├── 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 5 | #include 6 | #include 7 | 8 | class SocketSelect; 9 | class SocketBreaker { 10 | friend SocketSelect; 11 | public: 12 | SocketBreaker(); 13 | ~SocketBreaker(); 14 | 15 | bool IsCreateSuc() const; 16 | bool ReCreate(); 17 | 18 | bool IsBreak() const; 19 | 20 | bool Break(); 21 | bool Clear(); 22 | void Close(); 23 | 24 | WSAEVENT BreakerFD() const; 25 | 26 | private: 27 | SocketBreaker(const SocketBreaker&); 28 | SocketBreaker& operator=(const SocketBreaker&); 29 | 30 | private: 31 | std::mutex m_mutex; 32 | WSAEVENT m_event; 33 | bool m_create_success; 34 | bool m_broken; 35 | int m_exception; 36 | }; 37 | 38 | class SocketSelect { 39 | public: 40 | SocketSelect(SocketBreaker& _breaker, bool _autoclear = false); 41 | ~SocketSelect(); 42 | 43 | void PreSelect(); 44 | void Read_FD_SET(SOCKET _socket); 45 | void Write_FD_SET(SOCKET _socket); 46 | void Exception_FD_SET(SOCKET _socket); 47 | int Select(); 48 | int Select(int _msec); 49 | int Select(int _sec, int _usec); 50 | 51 | int Errno() const; 52 | 53 | int Read_FD_ISSET(SOCKET _socket) const; 54 | int Write_FD_ISSET(SOCKET _socket) const; 55 | int Exception_FD_ISSET(SOCKET _socket) const; 56 | 57 | bool IsBreak() const; 58 | bool IsException() const; 59 | 60 | SocketBreaker& Breaker(); 61 | 62 | private: 63 | SocketSelect(const SocketSelect&); 64 | SocketSelect& operator=(const SocketSelect&); 65 | 66 | private: 67 | const bool autoclear_; 68 | SocketBreaker& breaker_; 69 | bool m_broken; 70 | 71 | std::map m_filter_map; 72 | int errno_; 73 | 74 | fd_set writefd_; 75 | fd_set readfd_; 76 | fd_set exceptionfd_; 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /shadow_tls.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | Header Files 73 | 74 | 75 | -------------------------------------------------------------------------------- /socket_address.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making Mars available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | /* 15 | * socket_address.h 16 | * 17 | * Created on: 2014-12-1 18 | * Author: yerungui 19 | */ 20 | 21 | #ifndef SOCKET_ADDRESS_H_ 22 | #define SOCKET_ADDRESS_H_ 23 | 24 | #include 25 | #include 26 | #include // for socket_storage 27 | #include 28 | #include 29 | 30 | const char* socket_inet_ntop(int af, const void* src, char* dst, unsigned int size); 31 | int socket_inet_pton(int af, const char* src, void* dst); 32 | 33 | class socket_address { 34 | 35 | public: 36 | explicit socket_address(const char* _ip, uint16_t _port); 37 | explicit socket_address(const sockaddr_in& _addr); 38 | explicit socket_address(const sockaddr_in6& _addr); 39 | explicit socket_address(const sockaddr* _addr); 40 | explicit socket_address(const struct in_addr& _in_addr); 41 | explicit socket_address(const struct in6_addr& _in6_addr); 42 | explicit socket_address(const char* ipport); 43 | 44 | const sockaddr& address() const; 45 | socklen_t address_length() const; 46 | 47 | const char* url() const; 48 | const char* ip() const; 49 | const char* ipv6() const; 50 | uint16_t port() const; 51 | 52 | bool valid() const; 53 | bool valid_server_address(bool _allowloopback = false, bool _ignore_port = false) const; 54 | bool valid_broadcast_address() const; 55 | 56 | bool valid_loopback_ip() const; 57 | bool valid_broadcast_ip() const; 58 | 59 | bool isv4mapped_address() const; 60 | bool isv6() const; 61 | bool isv4() const; 62 | 63 | bool is_ipport_equal(const socket_address& _sa) const {return 0==strncmp(ip(), _sa.ip(), sizeof(ip_)) && port()==_sa.port();} 64 | 65 | public: 66 | static socket_address getsockname(SOCKET _sock); 67 | static socket_address getpeername(SOCKET _sock); 68 | 69 | private: 70 | // socket_address(const socket_address&); 71 | // const socket_address& operator=(const socket_address&); 72 | void __init(const sockaddr* _addr); 73 | 74 | const sockaddr_in* _asv4() const; 75 | const sockaddr_in6* _asv6() const; 76 | 77 | private: 78 | struct sockaddr_storage addr_; 79 | char ip_[96]; 80 | char url_[128]; 81 | }; 82 | 83 | #endif /* SOCKET_ADDRESS_H_ */ 84 | -------------------------------------------------------------------------------- /shadow_tls.cpp: -------------------------------------------------------------------------------- 1 | // shadow_tls.cpp : This file contains the 'main' function. Program execution begins and ends there. 2 | // 3 | 4 | #include "shadow_tls_client.h" 5 | #include "shadow_tls_server.h" 6 | 7 | #include "debug_helper.h" 8 | 9 | #include 10 | 11 | #include "socket_address.h" 12 | 13 | class ClientEvent : public MShadowEvent 14 | { 15 | public: 16 | void OnConnect() override 17 | { 18 | printf("connected\n"); 19 | } 20 | 21 | void OnDisConnect(bool isremote) override 22 | { 23 | printf("disconnected %s\n", isremote ? "because remote closed" : "locally"); 24 | } 25 | 26 | void OnError(int errcode) override 27 | { 28 | printf("error:%d\n", errcode); 29 | } 30 | }; 31 | 32 | class ServerEvent : public MShadowServer 33 | { 34 | public: 35 | void OnAccept(shadow_tls_server* server, SOCKET sock, const sockaddr_in& addr) override 36 | { 37 | char tmp[100] = {0}; 38 | socket_inet_ntop(AF_INET, &addr, tmp, sizeof(tmp)); 39 | printf("connect from %s\n", tmp); 40 | } 41 | 42 | void OnError(shadow_tls_server* server, int err) override 43 | { 44 | printf("error:%d\n", err); 45 | } 46 | }; 47 | 48 | ClientEvent g_client_event; 49 | ServerEvent g_server_event; 50 | 51 | void usage(char* pragma) 52 | { 53 | printf("%s client|server [option]\n", pragma); 54 | printf("option:\n"); 55 | printf("\tport for server default:9981\n"); 56 | 57 | printf("\tserver_address for client eg:192.168.2.206:9981\n"); 58 | printf("\tshadow_domain default:www.baidu.com\n"); 59 | } 60 | 61 | int main(int argc, char* argv[]) 62 | { 63 | if (argc < 2) 64 | { 65 | usage(argv[0]); 66 | return 1; 67 | } 68 | 69 | WSADATA wsa{}; 70 | WSAStartup(MAKEWORD(2, 2), &wsa); 71 | 72 | if (strcmp(argv[1], "client") == 0) 73 | { 74 | std::string shadow_address = "www.baidu.com"; 75 | if (argc == 4) 76 | { 77 | shadow_address = argv[3]; 78 | } 79 | shadow_tls_client cli(g_client_event); 80 | cli.connect(argv[2], shadow_address); 81 | std::this_thread::sleep_for(std::chrono::minutes(1)); 82 | } 83 | else if (strcmp(argv[1], "server") == 0) 84 | { 85 | unsigned short port = 9981; 86 | std::string shadow_address = "www.baidu.com:443"; 87 | if (argc >= 3) 88 | port = atoi(argv[2]); 89 | if (argc >= 4) 90 | shadow_address = argv[3]; 91 | 92 | debug_log("%d", port); 93 | shadow_tls_server srv(g_server_event, shadow_address); 94 | srv.start_server(port); 95 | std::this_thread::sleep_for(std::chrono::minutes(1)); 96 | } 97 | else 98 | { 99 | usage(argv[0]); 100 | return 1; 101 | } 102 | 103 | WSACleanup(); 104 | return 0; 105 | } 106 | 107 | // Run program: Ctrl + F5 or Debug > Start Without Debugging menu 108 | // Debug program: F5 or Debug > Start Debugging menu 109 | 110 | // Tips for Getting Started: 111 | // 1. Use the Solution Explorer window to add/manage files 112 | // 2. Use the Team Explorer window to connect to source control 113 | // 3. Use the Output window to see build output and other messages 114 | // 4. Use the Error List window to view errors 115 | // 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project 116 | // 6. In the future, to open this project again, go to File > Open > Project and select the .sln file 117 | -------------------------------------------------------------------------------- /autobuffer.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making Mars available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | 15 | #ifndef COMM_AUTOBUFFER_H_ 16 | #define COMM_AUTOBUFFER_H_ 17 | 18 | #include 19 | #include 20 | 21 | class AutoBuffer { 22 | public: 23 | enum TSeek { 24 | ESeekStart, 25 | ESeekCur, 26 | ESeekEnd, 27 | }; 28 | 29 | public: 30 | explicit AutoBuffer(size_t _size = 128); 31 | explicit AutoBuffer(void* _pbuffer, size_t _len, size_t _size = 128); 32 | explicit AutoBuffer(const void* _pbuffer, size_t _len, size_t _size = 128); 33 | ~AutoBuffer(); 34 | 35 | void AllocWrite(size_t _readytowrite, bool _changelength = true); 36 | void AddCapacity(size_t _len); 37 | 38 | template void Write(const T& _val) 39 | { Write(&_val, sizeof(_val));} 40 | 41 | template void Write(off_t& _pos, const T& _val) 42 | { Write(_pos, &_val, sizeof(_val));} 43 | 44 | template void Write(const off_t& _pos, const T& _val) 45 | { Write(_pos, &_val, sizeof(_val));} 46 | 47 | void Write(const char* const _val) 48 | { Write(_val, strlen(_val));} 49 | 50 | void Write(off_t& _pos, const char* const _val) 51 | { Write(_pos, _val, strlen(_val));} 52 | 53 | void Write(const off_t& _pos, const char* const _val) 54 | { Write(_pos, _val, strlen(_val));} 55 | 56 | void Write(const AutoBuffer& _buffer); 57 | void Write(const void* _pbuffer, size_t _len); 58 | void Write(off_t& _pos, const AutoBuffer& _buffer); 59 | void Write(off_t& _pos, const void* _pbuffer, size_t _len); 60 | void Write(const off_t& _pos, const AutoBuffer& _buffer); 61 | void Write(const off_t& _pos, const void* _pbuffer, size_t _len); 62 | void Write(TSeek _seek, const void* _pbuffer, size_t _len); 63 | 64 | template size_t Read(T& _val) 65 | { return Read(&_val, sizeof(_val)); } 66 | 67 | template size_t Read(off_t& _pos, T& _val) const 68 | { return Read(_pos, &_val, sizeof(_val)); } 69 | 70 | template size_t Read(const off_t& _pos, T& _val) const 71 | { return Read(_pos, &_val, sizeof(_val)); } 72 | 73 | size_t Read(void* _pbuffer, size_t _len); 74 | size_t Read(AutoBuffer& _rhs , size_t _len); 75 | 76 | size_t Read(off_t& _pos, void* _pbuffer, size_t _len) const; 77 | size_t Read(off_t& _pos, AutoBuffer& _rhs, size_t _len) const; 78 | 79 | size_t Read(const off_t& _pos, void* _pbuffer, size_t _len) const; 80 | size_t Read(const off_t& _pos, AutoBuffer& _rhs, size_t _len) const; 81 | 82 | off_t Move(off_t _move_len); 83 | 84 | void Seek(off_t _offset, TSeek _eorigin); 85 | void Length(off_t _pos, size_t _lenght); 86 | 87 | void* Ptr(off_t _offset=0); 88 | void* PosPtr(); 89 | const void* Ptr(off_t _offset=0) const; 90 | const void* PosPtr() const; 91 | 92 | off_t Pos() const; 93 | size_t PosLength() const; 94 | size_t Length() const; 95 | size_t Capacity() const; 96 | 97 | void Attach(void* _pbuffer, size_t _len); 98 | void Attach(AutoBuffer& _rhs); 99 | void* Detach(size_t* _plen = NULL); 100 | 101 | void Reset(); 102 | 103 | private: 104 | void __FitSize(size_t _len); 105 | 106 | private: 107 | AutoBuffer(const AutoBuffer& _rhs); 108 | AutoBuffer& operator = (const AutoBuffer& _rhs); 109 | 110 | private: 111 | unsigned char* parray_; 112 | off_t pos_; 113 | size_t length_; 114 | size_t capacity_; 115 | size_t malloc_unitsize_; 116 | }; 117 | 118 | extern const AutoBuffer KNullAtuoBuffer; 119 | 120 | template class copy_wrapper_helper; 121 | 122 | template <> 123 | class copy_wrapper_helper { 124 | public: 125 | static void copy_constructor(AutoBuffer& _lhs, AutoBuffer& _rhs) 126 | { _lhs.Attach(_rhs); } 127 | 128 | static void copy_constructor(AutoBuffer& _lhs, const AutoBuffer& _rhs) 129 | { _lhs.Attach(const_cast(_rhs)); } 130 | 131 | static void destructor(AutoBuffer& _delobj) {} 132 | }; 133 | 134 | #endif //COMM_AUTOBUFFER_H_ 135 | 136 | -------------------------------------------------------------------------------- /shadow_tls_server.cpp: -------------------------------------------------------------------------------- 1 | #include "shadow_tls_server.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "bio.h" 8 | #include "shadow_client.h" 9 | 10 | #include "debug_helper.h" 11 | 12 | #define DEFAULT_SHADOW_DOAMIN "www.google.com:443" 13 | 14 | int g_client_id = 0; 15 | 16 | DWORD WINAPI thread_client(LPVOID lpThreadParameter) 17 | { 18 | auto cli = static_cast(lpThreadParameter); 19 | while (true) 20 | { 21 | int ret = cli->handshake(); 22 | if (ret == -1) 23 | { 24 | debug_log("handshake to shadow domain failed\n"); 25 | return 1; 26 | } 27 | break; 28 | } 29 | return 0; 30 | } 31 | 32 | shadow_tls_server::shadow_tls_server(MShadowServer& observer) 33 | : shadow_doamin_(DEFAULT_SHADOW_DOAMIN) 34 | , shutdown_(false) 35 | , observer_(observer) 36 | { 37 | init(); 38 | } 39 | 40 | shadow_tls_server::shadow_tls_server(MShadowServer& observer, const std::string& shadow_domain) 41 | : shadow_doamin_(shadow_domain) 42 | , shutdown_(false) 43 | , observer_(observer) 44 | { 45 | init(); 46 | } 47 | 48 | shadow_tls_server::~shadow_tls_server() 49 | { 50 | shutdown_ = true; 51 | listen_thread_.join(); 52 | for (auto th = clients_.begin(); th != clients_.end(); ++th) 53 | { 54 | if (th->second.thread.joinable()) 55 | th->second.thread.join(); 56 | } 57 | 58 | { 59 | std::unique_lock lock(client_mutex_); 60 | clients_.clear(); 61 | } 62 | } 63 | 64 | int shadow_tls_server::start_server(uint16_t port) 65 | { 66 | int res = 0; 67 | do 68 | { 69 | if (port <= 0 || port >= 0xffff) 70 | break; 71 | socket_listen_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 72 | if (socket_listen_ == INVALID_SOCKET) 73 | { 74 | break; 75 | } 76 | SOCKADDR_IN si = {0}; 77 | si.sin_family = AF_INET; 78 | si.sin_port = ntohs(port); 79 | si.sin_addr.S_un.S_addr = ADDR_ANY; 80 | res = bind(socket_listen_, reinterpret_cast(&si), sizeof(si)); 81 | if (res == SOCKET_ERROR) 82 | { 83 | break; 84 | } 85 | res = listen(socket_listen_, SOMAXCONN); 86 | if (res == SOCKET_ERROR) 87 | { 88 | break; 89 | } 90 | 91 | listen_thread_ = std::thread([this] { listen_routine(); }); 92 | } 93 | while (false); 94 | return res; 95 | } 96 | 97 | void shadow_tls_server::shutdown() 98 | { 99 | shutdown_ = true; 100 | read_write_breaker_.Break(); 101 | } 102 | 103 | void shadow_tls_server::init() 104 | { 105 | } 106 | 107 | void shadow_tls_server::listen_routine() 108 | { 109 | int ret = 0; 110 | while (!shutdown_) 111 | { 112 | struct sockaddr_storage sock_addr; 113 | int len = sizeof(sock_addr); 114 | SOCKET c = accept(socket_listen_, reinterpret_cast(&sock_addr), &len); 115 | if (c == INVALID_SOCKET) 116 | { 117 | debug_log("accept %d\n", WSAGetLastError()); 118 | break; 119 | } 120 | g_client_id++; 121 | debug_log("%d new client %d\n", g_client_id, c); 122 | client_info client{}; 123 | client.id = g_client_id; 124 | client.s = c; 125 | DWORD dwThreadId = 0; 126 | client.thread = std::thread([&]() 127 | { 128 | client_routine(g_client_id); 129 | }); 130 | 131 | char cli_ip[16] = {0}; 132 | socket_inet_ntop(AF_INET, &(reinterpret_cast(&sock_addr)->sin_addr), cli_ip, 133 | sizeof(cli_ip)); 134 | observer_.OnAccept( 135 | this, c, 136 | *reinterpret_cast(&reinterpret_cast(&sock_addr)->sin_addr)); 137 | std::unique_lock lock(client_mutex_); 138 | clients_.insert({g_client_id, std::move(client)}); 139 | } 140 | } 141 | 142 | void shadow_tls_server::client_routine(int id) 143 | { 144 | int ret = 0; 145 | std::map::iterator it; 146 | 147 | { 148 | std::unique_lock lock(client_mutex_); 149 | it = clients_.find(id); 150 | if (it == clients_.end()) 151 | return; 152 | } 153 | 154 | debug_log("client routine %d begin\n", GetCurrentThreadId()); 155 | 156 | auto ctx = new routine_context(); 157 | ctx->type = kContextServer; 158 | ctx->src_sock = it->second.s; 159 | 160 | while (!shutdown_) 161 | { 162 | SocketSelect sel(read_write_breaker_, true); 163 | sel.PreSelect(); 164 | sel.Read_FD_SET(it->second.s); 165 | sel.Exception_FD_SET(it->second.s); 166 | if (!it->second.data.empty()) 167 | { 168 | sel.Write_FD_SET(it->second.s); 169 | } 170 | 171 | int retsel = sel.Select(3 * 1000); 172 | if (sel.IsException()) 173 | { 174 | continue; 175 | } 176 | 177 | if (sel.Exception_FD_ISSET(it->second.s)) 178 | { 179 | continue; 180 | } 181 | 182 | if (retsel < 0) 183 | { 184 | break; 185 | } 186 | 187 | 188 | if (sel.Write_FD_ISSET(it->second.s)) 189 | { 190 | if (!it->second.handshaked) 191 | { 192 | } 193 | int sent = ::send(it->second.s, (const char*)it->second.data.data(), it->second.data.size(), 0); 194 | if (sent <= 0) 195 | { 196 | break; 197 | } 198 | it->second.data.clear(); 199 | } 200 | 201 | if (sel.Read_FD_ISSET(it->second.s)) 202 | { 203 | if (!it->second.handshaked) 204 | { 205 | int err; 206 | auto cli = new shadow_client(ctx->src_sock); 207 | SOCKET remote = cli->connect(socket_address(shadow_doamin_.c_str()), err); 208 | if (remote == INVALID_SOCKET) 209 | { 210 | delete cli; 211 | debug_log("connect tls remote failed\n"); 212 | break; 213 | } 214 | ctx->dst_sock = remote; 215 | 216 | if (cli->handshake() < 0) 217 | { 218 | delete cli; 219 | debug_log("handshake failed\n"); 220 | break; 221 | } 222 | //DWORD thread_id = 0; 223 | //HANDLE handle = CreateThread(nullptr, 0, thread_client, cli, 0, &thread_id); 224 | //if(handle == nullptr) 225 | //{ 226 | // break; 227 | //} 228 | //WaitForSingleObject(handle, INFINITE); 229 | debug_log("handshake finished\n"); 230 | 231 | //OK GO GO GO 232 | delete cli; 233 | it->second.handshaked = true; 234 | } 235 | else 236 | { 237 | } 238 | } 239 | } 240 | observer_.OnError(this, WSAGetLastError()); 241 | debug_log("client routine %d end\n", GetCurrentThreadId()); 242 | } 243 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /autobuffer.cpp: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making Mars available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | #include "autobuffer.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "debug_helper.h" 21 | 22 | 23 | const AutoBuffer KNullAtuoBuffer; 24 | 25 | #ifndef max 26 | #define max(a, b) (((a) > (b)) ? (a) : (b)) 27 | #endif 28 | #ifndef min 29 | #define min(a, b) (((a) < (b)) ? (a) : (b)) 30 | #endif 31 | 32 | AutoBuffer::AutoBuffer(size_t _nSize) 33 | : parray_(NULL) 34 | , pos_(0) 35 | , length_(0) 36 | , capacity_(0) 37 | , malloc_unitsize_(_nSize) 38 | {} 39 | 40 | 41 | AutoBuffer::AutoBuffer(void* _pbuffer, size_t _len, size_t _nSize) 42 | : parray_(NULL) 43 | , pos_(0) 44 | , length_(0) 45 | , capacity_(0) 46 | , malloc_unitsize_(_nSize) { 47 | Attach(_pbuffer, _len); 48 | } 49 | 50 | AutoBuffer::AutoBuffer(const void* _pbuffer, size_t _len, size_t _nSize) 51 | : parray_(NULL) 52 | , pos_(0) 53 | , length_(0) 54 | , capacity_(0) 55 | , malloc_unitsize_(_nSize) { 56 | Write(0, _pbuffer, _len); 57 | } 58 | 59 | 60 | AutoBuffer::~AutoBuffer() { 61 | Reset(); 62 | } 63 | 64 | void AutoBuffer::AllocWrite(size_t _readytowrite, bool _changelength) { 65 | size_t nLen = Pos() + _readytowrite; 66 | __FitSize(nLen); 67 | 68 | if (_changelength) length_ = max(nLen, length_); 69 | } 70 | 71 | void AutoBuffer::AddCapacity(size_t _len) { 72 | __FitSize(Capacity() + _len); 73 | } 74 | 75 | void AutoBuffer::Write(const AutoBuffer& _buffer) { 76 | Write(_buffer.Ptr(), _buffer.Length()); 77 | } 78 | 79 | void AutoBuffer::Write(const void* _pbuffer, size_t _len) { 80 | Write(Pos(), _pbuffer, _len); 81 | Seek(_len, ESeekCur); 82 | } 83 | 84 | void AutoBuffer::Write(off_t& _pos, const AutoBuffer& _buffer) { 85 | Write((const off_t&) _pos, _buffer.Ptr(), _buffer.Length()); 86 | _pos += _buffer.Length(); 87 | } 88 | 89 | void AutoBuffer::Write(off_t& _pos, const void* _pbuffer, size_t _len) { 90 | Write((const off_t&) _pos, _pbuffer, _len); 91 | _pos += _len; 92 | } 93 | 94 | void AutoBuffer::Write(const off_t& _pos, const AutoBuffer& _buffer) { 95 | Write((const off_t&) _pos, _buffer.Ptr(), _buffer.Length()); 96 | } 97 | 98 | void AutoBuffer::Write(const off_t& _pos, const void* _pbuffer, size_t _len) { 99 | assert(NULL != _pbuffer || 0 == _len); 100 | assert(0 <= _pos); 101 | assert((size_t)_pos <= Length()); 102 | size_t nLen = _pos + _len; 103 | __FitSize(nLen); 104 | length_ = max(nLen, length_); 105 | memcpy((unsigned char*)Ptr() + _pos, _pbuffer, _len); 106 | } 107 | 108 | void AutoBuffer::Write(TSeek _seek, const void* _pbuffer, size_t _len){ 109 | off_t pos = 0; 110 | switch (_seek) { 111 | case ESeekStart: 112 | pos = 0; 113 | break; 114 | case ESeekCur: 115 | pos = pos_; 116 | break; 117 | case ESeekEnd: 118 | pos = length_; 119 | break; 120 | default: 121 | assert(false); 122 | break; 123 | } 124 | 125 | Write(pos, _pbuffer, _len); 126 | } 127 | 128 | size_t AutoBuffer::Read(void* _pbuffer, size_t _len) { 129 | size_t readlen = Read(Pos(), _pbuffer, _len); 130 | Seek(readlen, ESeekCur); 131 | return readlen; 132 | } 133 | 134 | size_t AutoBuffer::Read(AutoBuffer& _rhs , size_t _len) { 135 | size_t readlen = Read(Pos(), _rhs, _len); 136 | Seek(readlen, ESeekCur); 137 | return readlen; 138 | } 139 | 140 | size_t AutoBuffer::Read(off_t& _pos, void* _pbuffer, size_t _len) const { 141 | size_t readlen = Read((const off_t&) _pos, _pbuffer, _len); 142 | _pos += readlen; 143 | return readlen; 144 | } 145 | 146 | size_t AutoBuffer::Read(off_t& _pos, AutoBuffer& _rhs, size_t _len) const { 147 | size_t readlen = Read((const off_t&) _pos, _rhs, _len); 148 | _pos += readlen; 149 | return readlen; 150 | } 151 | 152 | size_t AutoBuffer::Read(const off_t& _pos, void* _pbuffer, size_t _len) const { 153 | assert(NULL != _pbuffer); 154 | assert(0 <= _pos); 155 | assert((size_t)_pos <= Length()); 156 | 157 | size_t readlen = Length() - _pos; 158 | readlen = min(readlen, _len); 159 | memcpy(_pbuffer, PosPtr(), readlen); 160 | return readlen; 161 | } 162 | 163 | size_t AutoBuffer::Read(const off_t& _pos, AutoBuffer& _rhs, size_t _len) const { 164 | size_t readlen = Length() - _pos; 165 | readlen = min(readlen, _len); 166 | _rhs.Write(PosPtr(), readlen); 167 | return readlen; 168 | } 169 | 170 | off_t AutoBuffer::Move(off_t _move_len) { 171 | if (0 < _move_len) { 172 | __FitSize(Length() + _move_len); 173 | memmove(parray_ + _move_len, parray_, Length()); 174 | memset(parray_, 0, _move_len); 175 | Length(Pos() + _move_len, Length() + _move_len); 176 | } else { 177 | size_t move_len = -_move_len; 178 | 179 | if (move_len > Length()) move_len = Length(); 180 | 181 | memmove(parray_, parray_ + move_len, Length() - move_len); 182 | Length(move_len < (size_t)Pos() ? Pos() - move_len : 0, Length() - move_len); 183 | } 184 | 185 | return Length(); 186 | } 187 | 188 | void AutoBuffer::Seek(off_t _offset, TSeek _eorigin) { 189 | switch (_eorigin) { 190 | case ESeekStart: 191 | pos_ = _offset; 192 | break; 193 | 194 | case ESeekCur: 195 | pos_ += _offset; 196 | break; 197 | 198 | case ESeekEnd: 199 | pos_ = length_ + _offset; 200 | break; 201 | 202 | default: 203 | assert(false); 204 | break; 205 | } 206 | 207 | if (pos_ < 0) 208 | pos_ = 0; 209 | 210 | if ((size_t)pos_ > length_) 211 | pos_ = length_; 212 | } 213 | 214 | void AutoBuffer::Length(off_t _pos, size_t _lenght) { 215 | assert(0 <= _pos); 216 | assert((size_t)_pos <= _lenght); 217 | assert(_lenght <= Capacity()); 218 | length_ = _lenght; 219 | Seek(_pos, ESeekStart); 220 | } 221 | 222 | void* AutoBuffer::Ptr(off_t _offset) { 223 | return (char*)parray_ + _offset; 224 | } 225 | 226 | const void* AutoBuffer::Ptr(off_t _offset) const { 227 | return (const char*)parray_ + _offset; 228 | } 229 | 230 | void* AutoBuffer::PosPtr() { 231 | return ((unsigned char*)Ptr()) + Pos(); 232 | } 233 | 234 | const void* AutoBuffer::PosPtr() const { 235 | return ((unsigned char*)Ptr()) + Pos(); 236 | } 237 | 238 | off_t AutoBuffer::Pos() const { 239 | return pos_; 240 | } 241 | 242 | size_t AutoBuffer::PosLength() const { 243 | return length_ - pos_; 244 | } 245 | 246 | size_t AutoBuffer::Length() const { 247 | return length_; 248 | } 249 | 250 | size_t AutoBuffer::Capacity() const { 251 | return capacity_; 252 | } 253 | 254 | void AutoBuffer::Attach(void* _pbuffer, size_t _len) { 255 | Reset(); 256 | parray_ = (unsigned char*)_pbuffer; 257 | length_ = _len; 258 | capacity_ = _len; 259 | } 260 | 261 | void AutoBuffer::Attach(AutoBuffer& _rhs) { 262 | Reset(); 263 | parray_ = _rhs.parray_; 264 | pos_ = _rhs.pos_; 265 | length_ = _rhs.length_; 266 | capacity_ = _rhs.capacity_; 267 | 268 | _rhs.parray_ = NULL; 269 | _rhs.Reset(); 270 | } 271 | 272 | void* AutoBuffer::Detach(size_t* _plen) { 273 | unsigned char* ret = parray_; 274 | parray_ = NULL; 275 | size_t nLen = Length(); 276 | 277 | if (NULL != _plen) 278 | *_plen = nLen; 279 | 280 | Reset(); 281 | return ret; 282 | } 283 | 284 | void AutoBuffer::Reset() { 285 | if (NULL != parray_) 286 | free(parray_); 287 | 288 | parray_ = NULL; 289 | pos_ = 0; 290 | length_ = 0; 291 | capacity_ = 0; 292 | } 293 | 294 | void AutoBuffer::__FitSize(size_t _len) { 295 | if (_len > capacity_) { 296 | size_t mallocsize = ((_len + malloc_unitsize_ -1)/malloc_unitsize_)*malloc_unitsize_ ; 297 | 298 | void* p = realloc(parray_, mallocsize); 299 | 300 | if (NULL == p) { 301 | debug_log("_len=%" PRIu64 ", m_nMallocUnitSize=%" PRIu64 ", nMallocSize=%" PRIu64", m_nCapacity=%" PRIu64, 302 | (uint64_t)_len, (uint64_t)malloc_unitsize_, (uint64_t)mallocsize, (uint64_t)capacity_); 303 | 304 | free(parray_); 305 | parray_ = NULL; 306 | capacity_ = 0; 307 | return; 308 | } 309 | 310 | parray_ = (unsigned char*) p; 311 | 312 | assert(parray_); 313 | 314 | memset(parray_+capacity_, 0, mallocsize-capacity_); 315 | capacity_ = mallocsize; 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /shadow_tls.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | Win32 8 | 9 | 10 | Release 11 | Win32 12 | 13 | 14 | Debug 15 | x64 16 | 17 | 18 | Release 19 | x64 20 | 21 | 22 | 23 | 16.0 24 | Win32Proj 25 | {5050c864-25e8-48fc-a846-4af455287b29} 26 | shadowtls 27 | 10.0 28 | 29 | 30 | 31 | Application 32 | true 33 | v142 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v142 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v142 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v142 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | false 79 | 80 | 81 | true 82 | 83 | 84 | false 85 | 86 | 87 | 88 | Level3 89 | true 90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 91 | true 92 | 93 | 94 | Console 95 | true 96 | 97 | 98 | 99 | 100 | Level3 101 | true 102 | true 103 | true 104 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Console 109 | true 110 | true 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | true 118 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 119 | true 120 | 121 | 122 | Console 123 | true 124 | 125 | 126 | 127 | 128 | Level3 129 | true 130 | true 131 | true 132 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 133 | true 134 | 135 | 136 | Console 137 | true 138 | true 139 | true 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /shadow_tls_client.cpp: -------------------------------------------------------------------------------- 1 | #include "shadow_tls_client.h" 2 | 3 | #include 4 | 5 | #include "autobuffer.h" 6 | 7 | #include "debug_helper.h" 8 | 9 | 10 | shadow_tls_client::shadow_tls_client(MShadowEvent& event) 11 | : event_(event) 12 | { 13 | will_disconnect_ = false; 14 | mbedtls_ctr_drbg_init(&ctr_drbg_); 15 | mbedtls_entropy_init(&entropy_); 16 | 17 | int res = mbedtls_ctr_drbg_seed(&ctr_drbg_, mbedtls_entropy_func, &entropy_, NULL, 0); 18 | if (0 != res) 19 | { 20 | debug_log("drbg init error = %d.\n", res); 21 | exit(1); 22 | } 23 | 24 | mbedtls_net_init(&net_ctx_); 25 | mbedtls_ssl_init(&ssl_ctx_); 26 | mbedtls_x509_crt_init(&ca_crt_); 27 | mbedtls_ssl_config_init(&ssl_conf_); 28 | 29 | res = mbedtls_ssl_config_defaults(&ssl_conf_, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, 30 | MBEDTLS_SSL_PRESET_DEFAULT); 31 | if (0 != res) 32 | { 33 | debug_log("clt conf set default error = %d.\n", res); 34 | exit(1); 35 | } 36 | 37 | mbedtls_ssl_conf_authmode(&ssl_conf_, MBEDTLS_SSL_VERIFY_NONE); 38 | mbedtls_ssl_conf_rng(&ssl_conf_, mbedtls_ctr_drbg_random, &ctr_drbg_); 39 | mbedtls_ssl_conf_min_version(&ssl_conf_, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); 40 | } 41 | 42 | shadow_tls_client::~shadow_tls_client() 43 | { 44 | mbedtls_net_free(&net_ctx_); 45 | mbedtls_x509_crt_free(&ca_crt_); 46 | mbedtls_ssl_free(&ssl_ctx_); 47 | mbedtls_ssl_config_free(&ssl_conf_); 48 | 49 | mbedtls_ctr_drbg_free(&ctr_drbg_); 50 | mbedtls_entropy_free(&entropy_); 51 | } 52 | 53 | int shadow_tls_client::connect(const std::string& server, const std::string& shadow_domain) 54 | { 55 | int res = 0; 56 | do 57 | { 58 | if (!validate_address(server)) 59 | { 60 | res = MBEDTLS_ERR_SSL_BAD_CONFIG; 61 | break; 62 | } 63 | std::string address, port; 64 | if (!split_address_to_ip_and_port(server, address, port)) 65 | { 66 | res = MBEDTLS_ERR_SSL_BAD_CONFIG; 67 | break; 68 | } 69 | debug_log("connect to %s:%s\n", address.c_str(), port.c_str()); 70 | res = mbedtls_net_connect(&net_ctx_, address.c_str(), port.c_str(), MBEDTLS_NET_PROTO_TCP); 71 | if (0 != res) 72 | { 73 | break; 74 | } 75 | 76 | res = mbedtls_ssl_setup(&ssl_ctx_, &ssl_conf_); 77 | if (0 != res) 78 | { 79 | break; 80 | } 81 | 82 | res = mbedtls_ssl_set_hostname(&ssl_ctx_, shadow_domain.c_str()); 83 | if (0 != res) 84 | { 85 | break; 86 | } 87 | bool hs_failed = false; 88 | mbedtls_ssl_set_bio(&ssl_ctx_, &net_ctx_, mbedtls_net_send, mbedtls_net_recv, NULL); 89 | debug_log("start handshake\n"); 90 | while ((res = mbedtls_ssl_handshake(&ssl_ctx_)) != 0) 91 | { 92 | if (res != MBEDTLS_ERR_SSL_WANT_READ && res != MBEDTLS_ERR_SSL_WANT_WRITE) 93 | { 94 | hs_failed = true; 95 | debug_log("mbedtls_ssl_handshake returned -0x%x\n", -res); 96 | break; 97 | } 98 | } 99 | if (hs_failed) 100 | { 101 | break; 102 | } 103 | 104 | res = 0; 105 | event_.OnConnect(); 106 | thread_ = std::thread(std::bind(&shadow_tls_client::io_thread, this)); 107 | } 108 | while (false); 109 | if (res != 0) 110 | { 111 | event_.OnError(res); 112 | } 113 | return res; 114 | } 115 | 116 | void shadow_tls_client::disconenct() 117 | { 118 | if (will_disconnect_) 119 | return; 120 | will_disconnect_ = true; 121 | } 122 | 123 | void shadow_tls_client::write(const void* buf, unsigned int len) 124 | { 125 | AutoBuffer* tmpbuff = new AutoBuffer; 126 | tmpbuff->Write(0, buf, len); 127 | 128 | std::unique_lock lock(write_mutex_); 129 | lst_buffer_.push_back(tmpbuff); 130 | } 131 | 132 | SSIZE_T shadow_tls_client::read(void* buf, unsigned int len) 133 | { 134 | std::unique_lock lock(read_disconnect_mutex_); 135 | if(lst_rv_buffer_.empty()) 136 | return 0; 137 | AutoBuffer& tmp = *lst_rv_buffer_.front(); 138 | auto read_bytes = tmp.Read(buf, len); 139 | delete lst_rv_buffer_.front(); 140 | lst_rv_buffer_.pop_front(); 141 | return read_bytes; 142 | } 143 | 144 | bool shadow_tls_client::validate_address(const std::string& server) 145 | { 146 | if (server.find(':') == std::string::npos) 147 | { 148 | return false; 149 | } 150 | return true; 151 | } 152 | 153 | bool shadow_tls_client::split_address_to_ip_and_port(const std::string& server, std::string& address, std::string& port) 154 | { 155 | auto pos = server.find(':'); 156 | address = server.substr(0, pos); 157 | port = server.substr(pos + 1); 158 | return true; 159 | } 160 | 161 | void shadow_tls_client::io_thread() 162 | { 163 | int ret = 0; 164 | uint32_t flag = MBEDTLS_NET_POLL_READ; 165 | bool write_again = false, read_again = false; 166 | while (true) 167 | { 168 | { 169 | std::unique_lock lock(write_mutex_); 170 | if (!lst_buffer_.empty()) 171 | flag = MBEDTLS_NET_POLL_WRITE; 172 | else 173 | flag = MBEDTLS_NET_POLL_READ; 174 | } 175 | ret = mbedtls_net_poll(&net_ctx_, flag, 300); 176 | if (0 == ret) 177 | { 178 | if(will_disconnect_) 179 | break; 180 | 181 | event_.OnDisConnect(false); 182 | continue; 183 | } 184 | if (0 > ret) 185 | { 186 | debug_log("mbedtls poll error:%#X\n", -ret); 187 | break; 188 | } 189 | if (ret != flag) 190 | { 191 | debug_log("mbedtls poll error:%#X\n", -ret); 192 | break; 193 | } 194 | 195 | if(write_again) 196 | { 197 | std::unique_lock lock(write_mutex_); 198 | AutoBuffer& buf = *lst_buffer_.front(); 199 | size_t len = buf.Length(); 200 | 201 | if (buf.Pos() < (off_t)len) 202 | { 203 | int send_len = mbedtls_ssl_write(&ssl_ctx_, (const unsigned char*)buf.PosPtr(), 204 | (size_t)(len - buf.Pos())); 205 | if (0 == send_len) 206 | { 207 | return; 208 | } 209 | if (0 > send_len) 210 | { 211 | if (ret != MBEDTLS_ERR_SSL_WANT_WRITE && 212 | ret != MBEDTLS_ERR_SSL_WANT_READ && 213 | ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS && 214 | ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) 215 | { 216 | return; 217 | } 218 | else if (MBEDTLS_ERR_SSL_WANT_WRITE == send_len) 219 | { 220 | flag = MBEDTLS_NET_POLL_WRITE; 221 | write_again = true; 222 | continue; 223 | } 224 | else if (MBEDTLS_ERR_SSL_WANT_READ == send_len) 225 | { 226 | flag = MBEDTLS_NET_POLL_READ; 227 | write_again = true; 228 | continue; 229 | } 230 | else 231 | { 232 | flag = MBEDTLS_NET_POLL_WRITE; 233 | write_again = true; 234 | continue; 235 | } 236 | } 237 | if (0 < send_len) 238 | { 239 | buf.Seek(send_len, AutoBuffer::ESeekCur); 240 | write_again = false; 241 | } 242 | } 243 | else 244 | { 245 | delete lst_buffer_.front(); 246 | lst_buffer_.pop_front(); 247 | } 248 | write_again = false; 249 | continue; 250 | } 251 | 252 | if(read_again) 253 | { 254 | AutoBuffer* tmp = new AutoBuffer(); 255 | tmp->AllocWrite(4096); 256 | ret = mbedtls_ssl_read(&ssl_ctx_, (unsigned char*)tmp->Ptr(), tmp->Length()); 257 | if (0 == ret) 258 | { 259 | delete tmp; 260 | return; 261 | } 262 | if (0 > ret) 263 | { 264 | if (MBEDTLS_ERR_SSL_WANT_READ == ret) 265 | { 266 | flag = MBEDTLS_NET_POLL_READ; 267 | read_again = true; 268 | continue; 269 | } 270 | if (MBEDTLS_ERR_SSL_WANT_WRITE == ret) 271 | { 272 | flag = MBEDTLS_NET_POLL_WRITE; 273 | read_again = true; 274 | } 275 | return; 276 | } 277 | if (0 < ret) 278 | { 279 | std::unique_lock lock(read_disconnect_mutex_); 280 | lst_rv_buffer_.push_back(tmp); 281 | } 282 | read_again = false; 283 | continue; 284 | } 285 | 286 | switch (flag) 287 | { 288 | case MBEDTLS_NET_POLL_READ: 289 | { 290 | AutoBuffer* tmp = new AutoBuffer(); 291 | tmp->AllocWrite(4096); 292 | ret = mbedtls_ssl_read(&ssl_ctx_, (unsigned char*)tmp->Ptr(), tmp->Length()); 293 | if(0 == ret) 294 | { 295 | delete tmp; 296 | event_.OnDisConnect(true); 297 | return; 298 | } 299 | if(0 > ret) 300 | { 301 | if(MBEDTLS_ERR_SSL_WANT_READ == ret) 302 | { 303 | flag = MBEDTLS_NET_POLL_READ; 304 | read_again = true; 305 | continue; 306 | } 307 | if(MBEDTLS_ERR_SSL_WANT_WRITE == ret) 308 | { 309 | flag = MBEDTLS_NET_POLL_WRITE; 310 | read_again = true; 311 | } 312 | return; 313 | } 314 | if(0 < ret) 315 | { 316 | std::unique_lock lock(read_disconnect_mutex_); 317 | lst_rv_buffer_.push_back(tmp); 318 | } 319 | } 320 | break; 321 | case MBEDTLS_NET_POLL_WRITE: 322 | { 323 | std::unique_lock lock(write_mutex_); 324 | AutoBuffer& buf = *lst_buffer_.front(); 325 | size_t len = buf.Length(); 326 | 327 | if (buf.Pos() < (off_t)len) 328 | { 329 | int send_len = mbedtls_ssl_write(&ssl_ctx_, (const unsigned char*)buf.PosPtr(), 330 | (size_t)(len - buf.Pos())); 331 | if (0 == send_len) 332 | { 333 | event_.OnDisConnect(true); 334 | return; 335 | } 336 | if (0 > send_len) 337 | { 338 | if (ret != MBEDTLS_ERR_SSL_WANT_WRITE && 339 | ret != MBEDTLS_ERR_SSL_WANT_READ && 340 | ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS && 341 | ret != MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) 342 | { 343 | return; 344 | } 345 | else if (MBEDTLS_ERR_SSL_WANT_WRITE == send_len) 346 | { 347 | flag = MBEDTLS_NET_POLL_WRITE; 348 | write_again = true; 349 | continue; 350 | } 351 | else if (MBEDTLS_ERR_SSL_WANT_READ == send_len) 352 | { 353 | flag = MBEDTLS_NET_POLL_READ; 354 | write_again = true; 355 | continue; 356 | } 357 | else 358 | { 359 | flag = MBEDTLS_NET_POLL_WRITE; 360 | write_again = true; 361 | continue; 362 | } 363 | } 364 | if( 0 < send_len) 365 | { 366 | buf.Seek(send_len, AutoBuffer::ESeekCur); 367 | write_again = false; 368 | } 369 | } 370 | else 371 | { 372 | delete lst_buffer_.front(); 373 | lst_buffer_.pop_front(); 374 | } 375 | } 376 | break; 377 | } 378 | } 379 | } 380 | 381 | -------------------------------------------------------------------------------- /socket_select.cpp: -------------------------------------------------------------------------------- 1 | #include "socket_select.h" 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "debug_helper.h" 8 | 9 | #define socket_errno WSAGetLastError() 10 | 11 | 12 | #define ASSERT2(exp, fmt, ...) \ 13 | do { \ 14 | if(!(exp)) { \ 15 | debug_log("%s " fmt, ##exp, __VA_ARGS__); } \ 16 | }while(false) 17 | 18 | static DWORD __SO_RCVTIMEO(SOCKET _sock) { 19 | DWORD optval = 0; 20 | int optlen = sizeof(optval); 21 | ASSERT2(0 == getsockopt(_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&optval, &optlen), "%d, %s\n", WSAGetLastError(), gai_strerror(socket_errno)); 22 | return optval; 23 | } 24 | 25 | static void __SO_RCVTIMEO(SOCKET _sock, DWORD _ms) { 26 | DWORD optval = _ms; 27 | int optlen = sizeof(optval); 28 | ASSERT2(0 == setsockopt(_sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&optval, optlen), "%d, %s\n", socket_errno, gai_strerror(socket_errno)); 29 | } 30 | 31 | static BOOL __WOULDBLOCK(SOCKET _sock) { 32 | DWORD ret = __SO_RCVTIMEO(_sock); 33 | 34 | if (0 == ret) { 35 | return true; 36 | } 37 | 38 | return ret & 0x1; 39 | } 40 | 41 | static void __WOULDBLOCK(SOCKET _sock, bool _block) { 42 | DWORD ret = __SO_RCVTIMEO(_sock); 43 | 44 | if (0 == ret) { 45 | ret = 60 * 1000; 46 | } 47 | 48 | __SO_RCVTIMEO(_sock, (ret & (~0x1)) + _block); 49 | } 50 | 51 | SocketBreaker::SocketBreaker() 52 | : m_broken(false) 53 | , m_create_success(true), m_exception(0) { 54 | ReCreate(); 55 | } 56 | 57 | SocketBreaker::~SocketBreaker() { 58 | Close(); 59 | } 60 | 61 | bool SocketBreaker::IsCreateSuc() const { 62 | return m_create_success; 63 | } 64 | 65 | bool SocketBreaker::ReCreate() { 66 | m_event = WSACreateEvent(); 67 | m_create_success = WSA_INVALID_EVENT != m_event; 68 | ASSERT2(m_create_success, "%d, %s\n", WSAGetLastError(), gai_strerror(WSAGetLastError())); 69 | m_exception = WSAGetLastError(); 70 | m_broken = !m_create_success; 71 | return m_create_success; 72 | } 73 | 74 | bool SocketBreaker::IsBreak() const { 75 | return m_broken; 76 | } 77 | 78 | bool SocketBreaker::Break() { 79 | std::unique_lock lock(m_mutex); 80 | bool ret = WSASetEvent(m_event); 81 | ASSERT2(ret, "%d, %s\n", WSAGetLastError(), gai_strerror(WSAGetLastError())); 82 | m_broken = ret; 83 | 84 | if (!ret) m_exception = WSAGetLastError(); 85 | 86 | return m_broken; 87 | } 88 | 89 | bool SocketBreaker::Clear() { 90 | std::unique_lock lock(m_mutex); 91 | 92 | if (!m_broken) return true; 93 | 94 | bool ret = WSAResetEvent(m_event); 95 | ASSERT2(ret, "%d, %s\n", WSAGetLastError(), gai_strerror(WSAGetLastError())); 96 | 97 | m_broken = !ret; 98 | 99 | if (!ret) m_exception = WSAGetLastError(); 100 | 101 | return ret; 102 | } 103 | 104 | void SocketBreaker::Close() { 105 | bool ret = WSACloseEvent(m_event); 106 | ASSERT2(ret, "%d, %s\n", WSAGetLastError(), gai_strerror(WSAGetLastError())); 107 | m_exception = WSAGetLastError(); 108 | m_event = WSA_INVALID_EVENT; 109 | m_broken = true; 110 | } 111 | 112 | WSAEVENT SocketBreaker::BreakerFD() const { 113 | return m_event; 114 | } 115 | 116 | /////////////////////////////////////////////////////////////////////////////////////////////////// 117 | SocketSelect::SocketSelect(SocketBreaker& _breaker, bool _autoclear) 118 | : autoclear_(_autoclear), breaker_(_breaker), m_broken(false), errno_(0) { 119 | // inital FD 120 | FD_ZERO(&writefd_); 121 | 122 | FD_ZERO(&readfd_); 123 | FD_ZERO(&exceptionfd_); 124 | } 125 | 126 | SocketSelect::~SocketSelect() 127 | {} 128 | 129 | void SocketSelect::PreSelect() { 130 | m_broken = false; 131 | m_filter_map.clear(); 132 | errno_ = 0; 133 | 134 | FD_ZERO(&writefd_); 135 | 136 | FD_ZERO(&readfd_); 137 | FD_ZERO(&exceptionfd_); 138 | } 139 | 140 | int SocketSelect::Select() { 141 | return Select(WSA_INFINITE); 142 | } 143 | 144 | int SocketSelect::Select(int _msec) { 145 | assert(-1 <= _msec); 146 | 147 | //create eventarray and socketarray 148 | WSAEVENT* eventarray = (WSAEVENT*)calloc(m_filter_map.size() + 1, sizeof(WSAEVENT)); 149 | SOCKET* socketarray = (SOCKET*)calloc(m_filter_map.size() + 1, sizeof(SOCKET)); 150 | eventarray[0] = Breaker().BreakerFD(); 151 | socketarray[0] = INVALID_SOCKET; 152 | 153 | int index = 1; 154 | 155 | for (std::map::iterator it = m_filter_map.begin(); it != m_filter_map.end(); ++it) { 156 | eventarray[index] = WSACreateEvent(); 157 | socketarray[index] = it->first; 158 | 159 | ASSERT2(WSA_INVALID_EVENT != eventarray[index], "%d, %s\n", WSAGetLastError(), gai_strerror(WSAGetLastError())); 160 | ASSERT2(SOCKET_ERROR != WSAEventSelect(it->first, eventarray[index], it->second), "%d, %s\n", WSAGetLastError(), gai_strerror(WSAGetLastError())); 161 | 162 | ++index; 163 | } 164 | 165 | 166 | // select 167 | SOCKET maxsocket = INVALID_SOCKET; 168 | 169 | for (std::map::iterator it = m_filter_map.begin(); it != m_filter_map.end(); ++it) { 170 | maxsocket = maxsocket == INVALID_SOCKET ? it->first : maxsocket; 171 | maxsocket = it->first > maxsocket ? it->first : maxsocket; 172 | 173 | if (it->second & (FD_READ | FD_ACCEPT | FD_CLOSE)) { 174 | FD_SET(it->first, &readfd_); 175 | } 176 | 177 | if (it->second & (FD_WRITE | FD_CONNECT)) { 178 | FD_SET(it->first, &writefd_); 179 | } 180 | 181 | if (it->second & (FD_CLOSE)) { 182 | FD_SET(it->first, &exceptionfd_); 183 | } 184 | } 185 | 186 | int ret = 0; 187 | // check socket first write select 188 | int new_WOULDBLOCK_count = 0; 189 | 190 | if (INVALID_SOCKET != maxsocket) { 191 | timeval timeout = {0, 0}; 192 | ret = select(maxsocket + 1, &readfd_, &writefd_, &exceptionfd_, &timeout); 193 | 194 | if (0 > ret) { 195 | errno_ = WSAGetLastError(); 196 | m_broken = Breaker().m_broken; 197 | 198 | if (autoclear_) Breaker().Clear(); 199 | 200 | debug_log("return select, ret=%d\n", ret); 201 | goto END; //free eventarray and socketarrary 202 | } 203 | 204 | if (0 < ret) { 205 | m_broken = Breaker().m_broken; 206 | 207 | if (autoclear_) Breaker().Clear(); 208 | goto END; //free eventarray and socketarrary 209 | } 210 | } 211 | 212 | 213 | for (std::map::iterator it = m_filter_map.begin(); it != m_filter_map.end(); ++it) { 214 | if (it->second & (FD_WRITE) && !__WOULDBLOCK(it->first)) { 215 | FD_SET(it->first, &writefd_); 216 | __WOULDBLOCK(it->first, true); 217 | ++new_WOULDBLOCK_count; 218 | debug_log("socket %d\n", it->first); 219 | } 220 | } 221 | 222 | if (0 < new_WOULDBLOCK_count) { 223 | debug_log("WOULDBLOCK FD_WRITE wait count:%d\n", new_WOULDBLOCK_count); 224 | m_broken = Breaker().m_broken; 225 | 226 | if (autoclear_) Breaker().Clear(); 227 | 228 | ret = new_WOULDBLOCK_count; 229 | goto END; //free eventarray and socketarrary 230 | } 231 | 232 | // WSAWaitForMultipleEvents 233 | ret = WSAWaitForMultipleEvents(m_filter_map.size() + 1, eventarray, FALSE, _msec, FALSE); 234 | ASSERT2(WSA_WAIT_FAILED != ret, "%d, %s\n", WSAGetLastError(), gai_strerror(WSAGetLastError())); 235 | 236 | if (WSA_WAIT_FAILED == ret) errno_ = WSAGetLastError(); 237 | 238 | if (WSA_WAIT_FAILED != ret && WSA_WAIT_TIMEOUT != ret && 0 < ret - WSA_WAIT_EVENT_0) { 239 | WSANETWORKEVENTS networkevents = {0}; 240 | int event_index = ret; 241 | ret = WSAEnumNetworkEvents(socketarray[event_index - WSA_WAIT_EVENT_0], eventarray[event_index - WSA_WAIT_EVENT_0], &networkevents); 242 | 243 | if (ret == SOCKET_ERROR) 244 | errno_ = WSAGetLastError(); 245 | else { 246 | SOCKET sock = socketarray[event_index - WSA_WAIT_EVENT_0]; 247 | 248 | if (networkevents.lNetworkEvents & (FD_WRITE | FD_CONNECT) && 0 != __SO_RCVTIMEO(sock)) { 249 | debug_log("WOULDBLOCK FD_WRITE notify sock:%d\n", sock); 250 | } 251 | 252 | if (m_filter_map[sock] & (FD_WRITE | FD_CONNECT) && networkevents.lNetworkEvents & (FD_WRITE | FD_CONNECT)) { 253 | FD_SET(sock, &writefd_); 254 | __WOULDBLOCK(sock, false); 255 | debug_log("FD_WRITE | FD_CONNECT\n"); 256 | } 257 | 258 | if (m_filter_map[sock] & (FD_READ | FD_ACCEPT) && networkevents.lNetworkEvents & (FD_READ | FD_ACCEPT)) { 259 | FD_SET(sock, &readfd_); 260 | debug_log("FD_READ | FD_ACCEPT\n"); 261 | } 262 | 263 | if (m_filter_map[sock] & (FD_READ | FD_ACCEPT) && networkevents.lNetworkEvents & FD_CLOSE && networkevents.iErrorCode[FD_CLOSE_BIT] == 0) { 264 | FD_SET(sock, &readfd_); 265 | debug_log("FD_READ | FD_ACCEPT\n"); 266 | } 267 | 268 | if (m_filter_map[sock] & (FD_CLOSE)) { 269 | for (int i = 0; i < FD_MAX_EVENTS; ++i) { 270 | if (networkevents.iErrorCode[i] != 0) { 271 | debug_log("selector exception, sock %d err %d\n",sock, networkevents.iErrorCode[i]); 272 | FD_SET(sock, &exceptionfd_); 273 | break; 274 | } 275 | } 276 | } 277 | } 278 | } else { 279 | debug_log("return WSAWaitForMultipleEvents, ret=%d\n", ret); 280 | } 281 | 282 | 283 | if (ret == WSA_WAIT_FAILED) ret = -1; 284 | else if (ret == SOCKET_ERROR) ret = -1; 285 | else if (ret == WSA_WAIT_TIMEOUT) ret = 0; 286 | else ret = 1; 287 | 288 | m_broken = Breaker().m_broken; 289 | 290 | if (autoclear_) Breaker().Clear(); 291 | 292 | END: 293 | //free eventarray and socketarray 294 | index = 1; 295 | 296 | for (std::map::iterator it = m_filter_map.begin(); it != m_filter_map.end(); ++it) { 297 | ASSERT2(WSACloseEvent(eventarray[index]), "%d, %s\n", WSAGetLastError(), gai_strerror(WSAGetLastError())); 298 | ++index; 299 | } 300 | 301 | free(eventarray); 302 | free(socketarray); 303 | 304 | return ret; 305 | } 306 | 307 | int SocketSelect::Select(int _sec, int _usec) { 308 | assert(0 <= _sec); 309 | assert(0 <= _usec); 310 | 311 | return Select(_sec * 1000 + _usec / 1000); 312 | } 313 | 314 | void SocketSelect::Read_FD_SET(SOCKET _socket) { 315 | m_filter_map[_socket] |= (FD_READ | FD_ACCEPT | FD_CLOSE); 316 | } 317 | 318 | void SocketSelect::Write_FD_SET(SOCKET _socket) { 319 | m_filter_map[_socket] |= (FD_WRITE | FD_CONNECT); 320 | } 321 | 322 | void SocketSelect::Exception_FD_SET(SOCKET _socket) { 323 | m_filter_map[_socket] |= (FD_CLOSE); 324 | } 325 | 326 | int SocketSelect::Read_FD_ISSET(SOCKET _socket) const { 327 | return FD_ISSET(_socket, &readfd_); 328 | } 329 | 330 | int SocketSelect::Write_FD_ISSET(SOCKET _socket) const { 331 | return FD_ISSET(_socket, &writefd_); 332 | } 333 | 334 | int SocketSelect::Exception_FD_ISSET(SOCKET _socket) const { 335 | return FD_ISSET(_socket, &exceptionfd_); 336 | } 337 | 338 | bool SocketSelect::IsException() const { 339 | return 0 != breaker_.m_exception; 340 | } 341 | 342 | bool SocketSelect::IsBreak() const { 343 | return m_broken; 344 | } 345 | 346 | SocketBreaker& SocketSelect::Breaker() { 347 | return breaker_; 348 | } 349 | 350 | int SocketSelect::Errno() const { 351 | return errno_; 352 | } 353 | 354 | -------------------------------------------------------------------------------- /shadow_client.cpp: -------------------------------------------------------------------------------- 1 | #include "shadow_client.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "bio.h" 7 | #include "autobuffer.h" 8 | 9 | #include "debug_helper.h" 10 | 11 | #pragma warning(disable: 4996) 12 | 13 | using ssize_t = SSIZE_T; 14 | 15 | #define socket_close closesocket 16 | #define socket_errno WSAGetLastError() 17 | 18 | #define SOCKET_ERRNO(error) WSA##error 19 | #define IS_NOBLOCK_WRITE_ERRNO(err) ((err) == SOCKET_ERRNO(EWOULDBLOCK)) 20 | #define IS_NOBLOCK_READ_ERRNO(err) ((err) == SOCKET_ERRNO(EWOULDBLOCK)) 21 | #define IS_NOBLOCK_CONNECT_ERRNO(err) ((err) == SOCKET_ERRNO(EWOULDBLOCK)) 22 | #define IS_NOBLOCK_SEND_ERRNO(err) IS_NOBLOCK_WRITE_ERRNO(err) 23 | 24 | enum RECORD_TYPE : unsigned char 25 | { 26 | recordTypeChangeCipherSpec = 20, 27 | recordTypeAlert = 21, 28 | recordTypeHandshake = 22, 29 | recordTypeApplicationData = 23, 30 | }; 31 | 32 | enum RECORD_VERSION : unsigned short 33 | { 34 | VersionTLS10 = 0x0301, 35 | VersionTLS11 = 0x0302, 36 | VersionTLS12 = 0x0303, 37 | VersionTLS13 = 0x0304, 38 | 39 | VersionSSL30 = 0x0300 40 | }; 41 | 42 | enum HANDSHAKE_TYPE: unsigned char 43 | { 44 | handshakeTypeClientHello = 1, 45 | handshakeTypeServerHello = 2, 46 | handshakeTypeCertificate = 11, 47 | handshakeTypeServerKeyExchange = 12, 48 | handshakeTypeServerHelloDone = 14, 49 | handshakeTypeClientKeyExchange = 16, 50 | handshakeTypeCertificateStatus = 22, 51 | }; 52 | 53 | #pragma pack(push, 1) 54 | struct record_layer 55 | { 56 | RECORD_TYPE content_type; 57 | RECORD_VERSION version; 58 | unsigned short len; 59 | }; 60 | 61 | struct handshake_protocol 62 | { 63 | HANDSHAKE_TYPE type; 64 | uint8_t len[3]; 65 | }; 66 | #pragma pack(pop) 67 | 68 | 69 | int socket_ipv6only(SOCKET _sock, int _only) 70 | { 71 | return setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&_only, sizeof(_only)); 72 | } 73 | 74 | int socket_set_nobio(SOCKET fd) 75 | { 76 | static const int noblock = 1; 77 | return ioctlsocket(fd, FIONBIO, (u_long*)&noblock); 78 | } 79 | 80 | int socket_error(SOCKET sock) 81 | { 82 | int error = 0; 83 | socklen_t len = sizeof(error); 84 | if (0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&error, &len)) 85 | { 86 | error = socket_errno; 87 | } 88 | return error; 89 | } 90 | 91 | shadow_client::shadow_client() 92 | : socket_(INVALID_SOCKET) 93 | , remote_socket_(INVALID_SOCKET) 94 | { 95 | init(); 96 | } 97 | 98 | shadow_client::shadow_client(SOCKET remote_sock) 99 | : socket_(INVALID_SOCKET) 100 | , remote_socket_(remote_sock) 101 | { 102 | init(); 103 | } 104 | 105 | shadow_client::~shadow_client() 106 | { 107 | breaker_.Break(); 108 | if (socket_ != INVALID_SOCKET) 109 | { 110 | shutdown(socket_, SD_BOTH); 111 | socket_close(socket_); 112 | socket_ = INVALID_SOCKET; 113 | } 114 | } 115 | 116 | SOCKET shadow_client::connect(const socket_address& _address, int& _errcode, 117 | int32_t _timeout/*ms*/) 118 | { 119 | SOCKET sock = connect_impl(_address, _errcode, _timeout); 120 | socket_ = sock; 121 | return sock; 122 | } 123 | 124 | int shadow_client::handshake() 125 | { 126 | int res = 0; 127 | int change_cipher_spec_done = 0; 128 | 129 | SOCKET source = remote_socket_; 130 | SOCKET dest = socket_; 131 | do 132 | { 133 | bool change = false; 134 | do 135 | { 136 | AutoBuffer header, body; 137 | res = read_fix_size(source, header, 5); 138 | if (res <= 0) 139 | { 140 | debug_log("read tls header failed\n"); 141 | break; 142 | } 143 | 144 | auto layer = reinterpret_cast(header.Ptr()); 145 | debug_log("content type:%d ver:0x%x len:%d\n", layer->content_type, layer->version, htons(layer->len)); 146 | res = ::send(dest, static_cast(header.Ptr()), header.Length(), 0); 147 | if (res <= 0) 148 | { 149 | debug_log("send tls header failed\n"); 150 | break; 151 | } 152 | 153 | res = read_fix_size(source, body, htons(layer->len)); 154 | if (res <= 0) 155 | { 156 | debug_log("read tls body failed\n"); 157 | break; 158 | } 159 | 160 | res = ::send(dest, static_cast(body.Ptr()), body.Length(), 0); 161 | if (res <= 0) 162 | { 163 | debug_log("send tls body failed\n"); 164 | break; 165 | } 166 | 167 | if (layer->content_type != recordTypeHandshake) 168 | { 169 | if (layer->content_type != recordTypeChangeCipherSpec) 170 | { 171 | debug_log("unexpected tls frame type:%d\n", layer->content_type); 172 | 173 | break; 174 | } 175 | } 176 | if (layer->content_type == recordTypeHandshake && htons(layer->len) == 0x20) 177 | { 178 | change_cipher_spec_done++; 179 | } 180 | 181 | change = true; 182 | } 183 | while (false); 184 | if (change_cipher_spec_done >= 2) 185 | break; 186 | 187 | if (change) 188 | { 189 | dest = remote_socket_; 190 | source = socket_; 191 | } 192 | else 193 | { 194 | dest = socket_; 195 | source = remote_socket_; 196 | } 197 | } 198 | while (true); 199 | return res; 200 | } 201 | 202 | int shadow_client::send(const void* _buffer, size_t _len, int& _errcode, 203 | int _timeout) 204 | { 205 | uint64_t start = GetTickCount64(); 206 | int32_t cost_time = 0; 207 | size_t sent_len = 0; 208 | 209 | SocketSelect sel(breaker_); 210 | 211 | while (true) 212 | { 213 | ssize_t nwrite = ::send(socket_, static_cast(_buffer) + sent_len, _len - sent_len, 0); 214 | if (nwrite == 0 || (0 > nwrite && !IS_NOBLOCK_SEND_ERRNO(socket_errno))) 215 | { 216 | _errcode = socket_errno; 217 | return -1; 218 | } 219 | 220 | if (0 < nwrite) sent_len += nwrite; 221 | 222 | if (sent_len >= _len) 223 | { 224 | _errcode = 0; 225 | return static_cast(sent_len); 226 | } 227 | 228 | sel.PreSelect(); 229 | sel.Write_FD_SET(socket_); 230 | sel.Exception_FD_SET(socket_); 231 | int ret = (0 <= _timeout) 232 | ? (sel.Select((_timeout > cost_time) ? (_timeout - cost_time) : 0)) 233 | : (sel.Select()); 234 | cost_time = static_cast(GetTickCount64() - start); 235 | 236 | if (ret < 0) 237 | { 238 | _errcode = sel.Errno(); 239 | return -1; 240 | } 241 | 242 | if (ret == 0) 243 | { 244 | _errcode = SOCKET_ERRNO(ETIMEDOUT); 245 | return static_cast(sent_len); 246 | } 247 | 248 | if (sel.IsException() || sel.IsBreak()) 249 | { 250 | _errcode = 0; 251 | return static_cast(sent_len); 252 | } 253 | 254 | if (sel.Exception_FD_ISSET(socket_)) 255 | { 256 | _errcode = socket_error(socket_); 257 | return -1; 258 | } 259 | 260 | if (!sel.Write_FD_ISSET(socket_)) 261 | { 262 | _errcode = socket_error(socket_); 263 | return -1; 264 | } 265 | } 266 | } 267 | 268 | int shadow_client::recv(SOCKET s, AutoBuffer& _buffer, size_t _max_size, int& _errcode, 269 | int _timeout, bool _wait_full_size) 270 | { 271 | uint64_t start = GetTickCount64(); 272 | int32_t cost_time = 0; 273 | size_t recv_len = 0; 274 | 275 | if (_buffer.Capacity() - _buffer.Length() < _max_size) 276 | { 277 | _buffer.AddCapacity(_max_size - (_buffer.Capacity() - _buffer.Length())); 278 | } 279 | 280 | 281 | SocketSelect sel(breaker_); 282 | while (true) 283 | { 284 | ssize_t nrecv = ::recv(s, static_cast(_buffer.Ptr(_buffer.Length() + recv_len)), _max_size - recv_len, 285 | 0); 286 | 287 | if (0 == nrecv) 288 | { 289 | _errcode = 0; 290 | _buffer.Length(_buffer.Pos(), _buffer.Length() + recv_len); 291 | return static_cast(recv_len); 292 | } 293 | 294 | if (0 > nrecv && !IS_NOBLOCK_READ_ERRNO(socket_errno)) 295 | { 296 | _errcode = socket_errno; 297 | return -1; 298 | } 299 | 300 | if (0 < nrecv) recv_len += nrecv; 301 | 302 | if (recv_len >= _max_size) 303 | { 304 | _buffer.Length(_buffer.Pos(), _buffer.Length() + recv_len); 305 | _errcode = 0; 306 | return static_cast(recv_len); 307 | } 308 | 309 | if (recv_len > 0 && !_wait_full_size) 310 | { 311 | _buffer.Length(_buffer.Pos(), _buffer.Length() + recv_len); 312 | _errcode = 0; 313 | return static_cast(recv_len); 314 | } 315 | 316 | sel.PreSelect(); 317 | sel.Read_FD_SET(s); 318 | sel.Exception_FD_SET(s); 319 | int ret = (0 <= _timeout) 320 | ? (sel.Select((_timeout > cost_time) ? (_timeout - cost_time) : 0)) 321 | : (sel.Select()); 322 | cost_time = static_cast(GetTickCount64() - start); 323 | 324 | if (ret < 0) 325 | { 326 | _errcode = sel.Errno(); 327 | return -1; 328 | } 329 | 330 | if (ret == 0) 331 | { 332 | _errcode = SOCKET_ERRNO(ETIMEDOUT); 333 | _buffer.Length(_buffer.Pos(), _buffer.Length() + recv_len); 334 | return static_cast(recv_len); 335 | } 336 | 337 | if (sel.IsException() || sel.IsBreak()) 338 | { 339 | _errcode = sel.Errno(); 340 | _buffer.Length(_buffer.Pos(), _buffer.Length() + recv_len); 341 | return static_cast(recv_len); 342 | } 343 | 344 | if (sel.Exception_FD_ISSET(s)) 345 | { 346 | _errcode = socket_error(s); 347 | return -1; 348 | } 349 | 350 | if (!sel.Read_FD_ISSET(s)) 351 | { 352 | _errcode = socket_error(s); 353 | return -1; 354 | } 355 | } 356 | } 357 | 358 | void shadow_client::cancel() 359 | { 360 | breaker_.Break(); 361 | } 362 | 363 | void shadow_client::init() 364 | { 365 | } 366 | 367 | int shadow_client::read_fix_size(SOCKET s, AutoBuffer& buffer, size_t size) 368 | { 369 | int ret, errcode; 370 | ret = recv(s, buffer, size, errcode, 3000, true); 371 | return ret; 372 | } 373 | 374 | SOCKET shadow_client::connect_impl(const socket_address& _address, int& _errcode, int32_t _timeout) 375 | { 376 | //socket 377 | SOCKET sock = socket(_address.address().sa_family, SOCK_STREAM, IPPROTO_TCP); 378 | 379 | if (sock == INVALID_SOCKET) 380 | { 381 | _errcode = socket_errno; 382 | return INVALID_SOCKET; 383 | } 384 | 385 | #ifdef _WIN32 386 | if (0 != socket_ipv6only(sock, 0)) { debug_log("set ipv6only failed. error %s\n", strerror(socket_errno)); } 387 | #endif 388 | 389 | /* 390 | int ret = socket_set_nobio(sock); 391 | if (ret != 0) 392 | { 393 | _errcode = socket_errno; 394 | ::socket_close(sock); 395 | return INVALID_SOCKET; 396 | } 397 | */ 398 | 399 | //connect 400 | int ret = ::connect(sock, &_address.address(), _address.address_length()); 401 | if (ret != 0 && !IS_NOBLOCK_CONNECT_ERRNO(socket_errno)) 402 | { 403 | _errcode = socket_errno; 404 | ::socket_close(sock); 405 | return INVALID_SOCKET; 406 | } 407 | 408 | SocketSelect sel(breaker_); 409 | sel.PreSelect(); 410 | sel.Write_FD_SET(sock); 411 | sel.Exception_FD_SET(sock); 412 | 413 | ret = (_timeout >= 0) ? (sel.Select(_timeout)) : (sel.Select()); 414 | if (ret == 0) 415 | { 416 | _errcode = SOCKET_ERRNO(ETIMEDOUT); 417 | ::socket_close(sock); 418 | return INVALID_SOCKET; 419 | } 420 | if (ret < 0) 421 | { 422 | _errcode = sel.Errno(); 423 | ::socket_close(sock); 424 | return INVALID_SOCKET; 425 | } 426 | 427 | if (sel.IsException()) 428 | { 429 | _errcode = 0; 430 | ::socket_close(sock); 431 | return INVALID_SOCKET; 432 | } 433 | if (sel.IsBreak()) 434 | { 435 | _errcode = 0; 436 | ::socket_close(sock); 437 | return INVALID_SOCKET; 438 | } 439 | 440 | if (sel.Exception_FD_ISSET(sock)) 441 | { 442 | _errcode = socket_error(sock); 443 | ::socket_close(sock); 444 | return INVALID_SOCKET; 445 | } 446 | 447 | if (!sel.Write_FD_ISSET(sock)) 448 | { 449 | _errcode = socket_error(sock); 450 | ::socket_close(sock); 451 | return INVALID_SOCKET; 452 | } 453 | _errcode = socket_error(sock); 454 | if (0 != _errcode) 455 | { 456 | ::socket_close(sock); 457 | return INVALID_SOCKET; 458 | } 459 | 460 | return sock; 461 | } 462 | 463 | int shadow_client::stream_data(SOCKET Source, SOCKET Dest) 464 | { 465 | int ret = 0; 466 | ssize_t len = 0; 467 | char dataBuffer[4096] = {0}; 468 | 469 | do 470 | { 471 | len = ::recv(Source, dataBuffer, sizeof(dataBuffer), 0); 472 | if (len > 0) 473 | { 474 | debug_log("<<< %zu bytes received\n", len); 475 | len = ::send(Dest, dataBuffer, len, 0); 476 | if (len >= 0) 477 | debug_log(">>> %zu bytes sent\n", len); 478 | } 479 | 480 | if (len == -1) 481 | ret = -1; 482 | } 483 | while (len > 0); 484 | 485 | return ret; 486 | } 487 | -------------------------------------------------------------------------------- /socket_address.cpp: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making Mars available. 2 | // Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. 3 | 4 | // Licensed under the MIT License (the "License"); you may not use this file except in 5 | // compliance with the License. You may obtain a copy of the License at 6 | // http://opensource.org/licenses/MIT 7 | 8 | // Unless required by applicable law or agreed to in writing, software distributed under the License is 9 | // distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 10 | // either express or implied. See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | 13 | 14 | /* 15 | * socket_address.cpp 16 | * 17 | * Created on: 2014-12-1 18 | * Author: yerungui 19 | */ 20 | 21 | #include "socket_address.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "debug_helper.h" 30 | 31 | #pragma warning(disable: 4996) 32 | 33 | #define NS_INADDRSZ 4 34 | typedef unsigned int uint32; 35 | typedef int int32; 36 | typedef unsigned short uint16; // NOLINT 37 | typedef short int16; // NOLINT 38 | 39 | inline bool IN6_IS_ADDR_NAT64(in6_addr* a6) 40 | { 41 | return a6->s6_words[0] == htons(0x0064) && a6->s6_words[1] == htons(0x0064); 42 | } 43 | 44 | 45 | #if defined(__linux__) && !defined(AI_DEFAULT) 46 | #define AI_DEFAULT (AI_V4MAPPED | AI_ADDRCONFIG) 47 | #endif 48 | 49 | static const char kWellKnownNat64Prefix[] = {'6', '4', ':', 'f', 'f', '9', 'b', ':', ':', '\0'}; 50 | 51 | static int socket_inet_pton4(const char* src, void* dst) 52 | { 53 | static const char digits[] = "0123456789"; 54 | int saw_digit, octets, ch; 55 | unsigned char tmp[NS_INADDRSZ], *tp; 56 | 57 | saw_digit = 0; 58 | octets = 0; 59 | *(tp = tmp) = 0; 60 | while ((ch = *src++) != '\0') 61 | { 62 | const char* pch; 63 | 64 | if ((pch = strchr(digits, ch)) != NULL) 65 | { 66 | size_t newNum = *tp * 10 + (pch - digits); 67 | 68 | if (newNum > 255) 69 | return (0); 70 | *tp = (unsigned char)newNum; 71 | if (! saw_digit) 72 | { 73 | if (++octets > 4) 74 | return (0); 75 | saw_digit = 1; 76 | } 77 | } 78 | else if (ch == '.' && saw_digit) 79 | { 80 | if (octets == 4) 81 | return (0); 82 | *++tp = 0; 83 | saw_digit = 0; 84 | } 85 | else 86 | return (0); 87 | } 88 | if (octets < 4) 89 | return (0); 90 | memcpy(dst, tmp, NS_INADDRSZ); 91 | return (1); 92 | } 93 | 94 | //https://chromium.googlesource.com/external/webrtc/+/edc6e57a92d2b366871f4c2d2e926748326017b9/webrtc/base/win32.cc 95 | // Helper function for inet_pton for IPv6 addresses. 96 | static int socket_inet_pton6(const char* src, void* dst) 97 | { 98 | // sscanf will pick any other invalid chars up, but it parses 0xnnnn as hex. 99 | // Check for literal x in the input string. 100 | const char* readcursor = src; 101 | char c = *readcursor++; 102 | while (c) 103 | { 104 | if (c == 'x') 105 | { 106 | return 0; 107 | } 108 | c = *readcursor++; 109 | } 110 | readcursor = src; 111 | struct in6_addr an_addr; 112 | memset(&an_addr, 0, sizeof(an_addr)); 113 | uint16* addr_cursor = (uint16*)(&an_addr.s6_addr[0]); 114 | uint16* addr_end = (uint16*)(&an_addr.s6_addr[16]); 115 | int seencompressed = 0; //false c89 not define bool type 116 | // Addresses that start with "::" (i.e., a run of initial zeros) or 117 | // "::ffff:" can potentially be IPv4 mapped or compatibility addresses. 118 | // These have dotted-style IPv4 addresses on the end (e.g. "::192.168.7.1"). 119 | if (*readcursor == ':' && *(readcursor + 1) == ':' && 120 | *(readcursor + 2) != 0) 121 | { 122 | // Check for periods, which we'll take as a sign of v4 addresses. 123 | const char* addrstart = readcursor + 2; 124 | if (strchr(addrstart, '.')) 125 | { 126 | const char* colon = strchr(addrstart, ':'); 127 | if (colon) 128 | { 129 | uint16 a_short; 130 | int bytesread = 0; 131 | if (sscanf(addrstart, "%hx%n", &a_short, &bytesread) != 1 || 132 | a_short != 0xFFFF || bytesread != 4) 133 | { 134 | // Colons + periods means has to be ::ffff:a.b.c.d. But it wasn't. 135 | return 0; 136 | } 137 | else 138 | { 139 | an_addr.s6_addr[10] = 0xFF; 140 | an_addr.s6_addr[11] = 0xFF; 141 | addrstart = colon + 1; 142 | } 143 | } 144 | struct in_addr v4; 145 | if (socket_inet_pton4(addrstart, &v4.s_addr)) 146 | { 147 | memcpy(&an_addr.s6_addr[12], &v4, sizeof(v4)); 148 | memcpy(dst, &an_addr, sizeof(an_addr)); 149 | return 1; 150 | } 151 | else 152 | { 153 | // Invalid v4 address. 154 | return 0; 155 | } 156 | } 157 | } 158 | // For addresses without a trailing IPv4 component ('normal' IPv6 addresses). 159 | while (*readcursor != 0 && addr_cursor < addr_end) 160 | { 161 | if (*readcursor == ':') 162 | { 163 | if (*(readcursor + 1) == ':') 164 | { 165 | if (seencompressed) 166 | { 167 | // Can only have one compressed run of zeroes ("::") per address. 168 | return 0; 169 | } 170 | // Hit a compressed run. Count colons to figure out how much of the 171 | // address is skipped. 172 | readcursor += 2; 173 | const char* coloncounter = readcursor; 174 | int coloncount = 0; 175 | if (*coloncounter == 0) 176 | { 177 | // Special case - trailing ::. 178 | addr_cursor = addr_end; 179 | } 180 | else 181 | { 182 | while (*coloncounter) 183 | { 184 | if (*coloncounter == ':') 185 | { 186 | ++coloncount; 187 | } 188 | ++coloncounter; 189 | } 190 | // (coloncount + 1) is the number of shorts left in the address. 191 | addr_cursor = addr_end - (coloncount + 1); 192 | seencompressed = 1; 193 | } 194 | } 195 | else 196 | { 197 | ++readcursor; 198 | } 199 | } 200 | else 201 | { 202 | uint16 word; 203 | int bytesread = 0; 204 | if (sscanf(readcursor, "%hx%n", &word, &bytesread) != 1) 205 | { 206 | return 0; 207 | } 208 | else 209 | { 210 | *addr_cursor = htons(word); 211 | ++addr_cursor; 212 | readcursor += bytesread; 213 | if (*readcursor != ':' && *readcursor != '\0') 214 | { 215 | return 0; 216 | } 217 | } 218 | } 219 | } 220 | if (*readcursor != '\0' || addr_cursor < addr_end) 221 | { 222 | // Catches addresses too short or too long. 223 | return 0; 224 | } 225 | memcpy(dst, &an_addr, sizeof(an_addr)); 226 | return 1; 227 | } 228 | 229 | int socket_inet_pton(int af, const char* src, void* dst) 230 | { 231 | // if (IsWindows7OrGreater()){ 232 | // return inet_pton(af, src, dst); 233 | // } 234 | 235 | // for OS below WINDOWS 7 236 | switch (af) 237 | { 238 | case AF_INET: 239 | return socket_inet_pton4(src, dst); 240 | case AF_INET6: 241 | return socket_inet_pton6(src, dst); 242 | default: 243 | //xerror("EAFNOSUPPORT"); 244 | return 0; 245 | } 246 | } 247 | 248 | static const char* inet_ntop_v4(const void* src, char* dst, socklen_t size) 249 | { 250 | const char digits[] = "0123456789"; 251 | int i; 252 | struct in_addr* addr = (struct in_addr*)src; 253 | u_long a = ntohl(addr->s_addr); 254 | const char* orig_dst = dst; 255 | 256 | if (size < 16) 257 | { 258 | //xerror("ENOSPC: size = %0", size); 259 | return NULL; 260 | } 261 | for (i = 0; i < 4; ++i) 262 | { 263 | int n = (a >> (24 - i * 8)) & 0xFF; 264 | int non_zerop = 0; 265 | 266 | if (non_zerop || n / 100 > 0) 267 | { 268 | *dst++ = digits[n / 100]; 269 | n %= 100; 270 | non_zerop = 1; 271 | } 272 | if (non_zerop || n / 10 > 0) 273 | { 274 | *dst++ = digits[n / 10]; 275 | n %= 10; 276 | non_zerop = 1; 277 | } 278 | *dst++ = digits[n]; 279 | if (i != 3) 280 | *dst++ = '.'; 281 | } 282 | *dst++ = '\0'; 283 | return orig_dst; 284 | } 285 | 286 | // Helper function for inet_ntop for IPv6 addresses. 287 | static const char* inet_ntop_v6(const void* src, char* dst, socklen_t size) 288 | { 289 | if (size < INET6_ADDRSTRLEN) 290 | { 291 | return NULL; 292 | } 293 | const uint16* as_shorts = 294 | reinterpret_cast(src); 295 | int runpos[8]; 296 | int current = 1; 297 | int max = 1; 298 | int maxpos = -1; 299 | int run_array_size = sizeof(runpos) / sizeof(runpos[0]); 300 | // Run over the address marking runs of 0s. 301 | for (int i = 0; i < run_array_size; ++i) 302 | { 303 | if (as_shorts[i] == 0) 304 | { 305 | runpos[i] = current; 306 | if (current > max) 307 | { 308 | maxpos = i; 309 | max = current; 310 | } 311 | ++current; 312 | } 313 | else 314 | { 315 | runpos[i] = -1; 316 | current = 1; 317 | } 318 | } 319 | if (max > 1) 320 | { 321 | int tmpmax = maxpos; 322 | // Run back through, setting -1 for all but the longest run. 323 | for (int i = run_array_size - 1; i >= 0; i--) 324 | { 325 | if (i > tmpmax) 326 | { 327 | runpos[i] = -1; 328 | } 329 | else if (runpos[i] == -1) 330 | { 331 | // We're less than maxpos, we hit a -1, so the 'good' run is done. 332 | // Setting tmpmax -1 means all remaining positions get set to -1. 333 | tmpmax = -1; 334 | } 335 | } 336 | } 337 | char* cursor = dst; 338 | // Print IPv4 compatible and IPv4 mapped addresses using the IPv4 helper. 339 | // These addresses have an initial run of either eight zero-bytes followed 340 | // by 0xFFFF, or an initial run of ten zero-bytes. 341 | if (runpos[0] == 1 && (maxpos == 5 || 342 | (maxpos == 4 && as_shorts[5] == 0xFFFF))) 343 | { 344 | *cursor++ = ':'; 345 | *cursor++ = ':'; 346 | if (maxpos == 4) 347 | { 348 | cursor += snprintf(cursor, INET6_ADDRSTRLEN - 2, "ffff:"); 349 | } 350 | const struct in_addr* as_v4 = 351 | reinterpret_cast(&(as_shorts[6])); 352 | inet_ntop_v4(as_v4, cursor, 353 | static_cast(INET6_ADDRSTRLEN - (cursor - dst))); 354 | } 355 | else 356 | { 357 | for (int i = 0; i < run_array_size; ++i) 358 | { 359 | if (runpos[i] == -1) 360 | { 361 | cursor += snprintf(cursor, 362 | INET6_ADDRSTRLEN - (cursor - dst), 363 | "%x", ntohs(as_shorts[i])); 364 | if (i != 7 && runpos[i + 1] != 1) 365 | { 366 | *cursor++ = ':'; 367 | } 368 | } 369 | else if (runpos[i] == 1) 370 | { 371 | // Entered the run; print the colons and skip the run. 372 | *cursor++ = ':'; 373 | *cursor++ = ':'; 374 | i += (max - 1); 375 | } 376 | } 377 | } 378 | return dst; 379 | } 380 | 381 | const char* socket_inet_ntop(int af, const void* src, char* dst, unsigned int size) 382 | { 383 | // if (IsWindows7OrGreater()){ 384 | // return inet_ntop(af, (PVOID)src, dst, size); 385 | // } 386 | 387 | // for OS below WINDOWS 7 388 | switch (af) 389 | { 390 | case AF_INET: 391 | return inet_ntop_v4(src, dst, size); 392 | case AF_INET6: 393 | return inet_ntop_v6(src, dst, size); 394 | default: 395 | //xerror("EAFNOSUPPORT"); 396 | return NULL; 397 | } 398 | } 399 | 400 | socket_address::socket_address(const char* _ip, uint16_t _port) 401 | { 402 | in6_addr addr6 = IN6ADDR_ANY_INIT; 403 | in_addr addr4 = {0}; 404 | 405 | if (socket_inet_pton(AF_INET, _ip, &addr4)) 406 | { 407 | sockaddr_in sock_addr = {0}; 408 | sock_addr.sin_family = AF_INET; 409 | sock_addr.sin_addr = addr4; 410 | sock_addr.sin_port = htons(_port); 411 | 412 | __init((sockaddr*)&sock_addr); 413 | } 414 | else if (socket_inet_pton(AF_INET6, _ip, &addr6)) 415 | { 416 | sockaddr_in6 sock_addr = {0}; 417 | sock_addr.sin6_family = AF_INET6; 418 | sock_addr.sin6_addr = addr6; 419 | sock_addr.sin6_port = htons(_port); 420 | 421 | __init((sockaddr*)&sock_addr); 422 | } 423 | else 424 | { 425 | struct addrinfo hints, * result, * rp; 426 | memset(&hints, 0, sizeof(hints)); 427 | hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ 428 | hints.ai_socktype = SOCK_STREAM; /* Datagram socket */ 429 | hints.ai_flags |= AI_CANONNAME; /* For wildcard IP address */ 430 | 431 | int ret = getaddrinfo(_ip, nullptr, &hints, &result); 432 | if (0 == ret) 433 | { 434 | for (rp = result; rp != NULL; rp = rp->ai_next) 435 | { 436 | sockaddr_in sock_addr = { 0 }; 437 | sock_addr.sin_family = AF_INET; 438 | sock_addr.sin_addr = ((struct sockaddr_in*)rp->ai_addr)->sin_addr; 439 | sock_addr.sin_port = htons(_port); 440 | 441 | __init((sockaddr*)&sock_addr); 442 | break; 443 | } 444 | freeaddrinfo(result); 445 | } 446 | else 447 | { 448 | sockaddr sock_addr = { 0 }; 449 | sock_addr.sa_family = AF_UNSPEC; 450 | __init((sockaddr*)&sock_addr); 451 | } 452 | } 453 | } 454 | 455 | socket_address::socket_address(const sockaddr_in& _addr) 456 | { 457 | __init((sockaddr*)&_addr); 458 | } 459 | 460 | socket_address::socket_address(const sockaddr_in6& _addr) 461 | { 462 | __init((sockaddr*)&_addr); 463 | } 464 | 465 | socket_address::socket_address(const sockaddr* _addr) 466 | { 467 | __init(_addr); 468 | } 469 | 470 | socket_address::socket_address(const struct in_addr& _in_addr) 471 | { 472 | sockaddr_in addr = {0}; 473 | addr.sin_family = AF_INET; 474 | addr.sin_addr = _in_addr; 475 | __init((sockaddr*)&addr); 476 | } 477 | 478 | socket_address::socket_address(const struct in6_addr& _in6_addr) 479 | { 480 | sockaddr_in6 addr6 = {0}; 481 | addr6.sin6_family = AF_INET6; 482 | addr6.sin6_addr = _in6_addr; 483 | __init((sockaddr*)&addr6); 484 | } 485 | 486 | socket_address::socket_address(const char* ipport) 487 | { 488 | std::vector splitted; 489 | char *dupstr = strdup(ipport); 490 | char* pos = strtok(dupstr, ":"); 491 | while (pos != nullptr) 492 | { 493 | splitted.push_back(pos); 494 | pos = strtok(nullptr, ":"); 495 | } 496 | free(dupstr); 497 | 498 | const char* _ip = splitted[0].c_str(); 499 | uint16 _port = atoi(splitted[1].c_str()); 500 | in6_addr addr6 = IN6ADDR_ANY_INIT; 501 | in_addr addr4 = {0}; 502 | 503 | if (socket_inet_pton(AF_INET, _ip, &addr4)) 504 | { 505 | sockaddr_in sock_addr = {0}; 506 | sock_addr.sin_family = AF_INET; 507 | sock_addr.sin_addr = addr4; 508 | sock_addr.sin_port = htons(_port); 509 | 510 | __init((sockaddr*)&sock_addr); 511 | } 512 | else if (socket_inet_pton(AF_INET6, _ip, &addr6)) 513 | { 514 | sockaddr_in6 sock_addr = {0}; 515 | sock_addr.sin6_family = AF_INET6; 516 | sock_addr.sin6_addr = addr6; 517 | sock_addr.sin6_port = htons(_port); 518 | 519 | __init((sockaddr*)&sock_addr); 520 | } 521 | else 522 | { 523 | struct addrinfo hints, * result, * rp; 524 | memset(&hints, 0, sizeof(hints)); 525 | hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ 526 | hints.ai_socktype = SOCK_STREAM; /* Datagram socket */ 527 | hints.ai_flags |= AI_CANONNAME; /* For wildcard IP address */ 528 | 529 | int ret = getaddrinfo(_ip, nullptr, &hints, &result); 530 | if (0 == ret) 531 | { 532 | for (rp = result; rp != NULL; rp = rp->ai_next) 533 | { 534 | sockaddr_in sock_addr = { 0 }; 535 | sock_addr.sin_family = AF_INET; 536 | sock_addr.sin_addr = ((struct sockaddr_in*)rp->ai_addr)->sin_addr; 537 | sock_addr.sin_port = htons(_port); 538 | 539 | __init((sockaddr*)&sock_addr); 540 | break; 541 | } 542 | freeaddrinfo(result); 543 | } 544 | else 545 | { 546 | sockaddr sock_addr = { 0 }; 547 | sock_addr.sa_family = AF_UNSPEC; 548 | __init((sockaddr*)&sock_addr); 549 | } 550 | } 551 | } 552 | 553 | void socket_address::__init(const sockaddr* _addr) 554 | { 555 | memset(&addr_, 0, sizeof(addr_)); 556 | memset(ip_, 0, sizeof(ip_)); 557 | memset(url_, 0, sizeof(url_)); 558 | 559 | if (AF_INET == _addr->sa_family) 560 | { 561 | memcpy(&addr_, _addr, sizeof(sockaddr_in)); 562 | socket_inet_ntop(_asv4()->sin_family, &_asv4()->sin_addr, ip_, sizeof(ip_)); 563 | snprintf(url_, sizeof(url_), "%s:%u", ip_, port()); 564 | } 565 | else if (AF_INET6 == _addr->sa_family) 566 | { 567 | memcpy(&addr_, _addr, sizeof(sockaddr_in6)); 568 | if (IN6_IS_ADDR_NAT64(const_cast(&_asv6()->sin6_addr))) 569 | { 570 | strncpy(ip_, kWellKnownNat64Prefix, 9); 571 | sockaddr_in addr = {0}; 572 | addr.sin_family = AF_INET; 573 | addr.sin_addr.s_addr = _asv6()->sin6_addr.u.Byte[12]; 574 | socket_inet_ntop(_asv6()->sin6_family, &(_asv6()->sin6_addr), ip_ + 9, sizeof(ip_) - 9); 575 | } 576 | else 577 | { 578 | socket_inet_ntop(_asv6()->sin6_family, &(_asv6()->sin6_addr), ip_, sizeof(ip_)); 579 | } 580 | 581 | snprintf(url_, sizeof(url_), "[%s]:%u", ip_, port()); 582 | } 583 | else 584 | { 585 | addr_.ss_family = AF_UNSPEC; 586 | } 587 | } 588 | 589 | const sockaddr& socket_address::address() const 590 | { 591 | //if (ELocalIPStack_IPv6==local_ipstack_detect()) 592 | // return address_fix(); 593 | return (sockaddr&)addr_; 594 | } 595 | 596 | socklen_t socket_address::address_length() const 597 | { 598 | if (AF_INET == addr_.ss_family) 599 | { 600 | return sizeof(sockaddr_in); 601 | } 602 | else if (AF_INET6 == addr_.ss_family) 603 | { 604 | return sizeof(sockaddr_in6); 605 | } 606 | 607 | return 0; 608 | } 609 | 610 | const char* socket_address::url() const 611 | { 612 | return url_; 613 | } 614 | 615 | const char* socket_address::ip() const 616 | { 617 | if (AF_INET == addr_.ss_family) 618 | { 619 | return ip_; 620 | } 621 | else if (AF_INET6 == addr_.ss_family) 622 | { 623 | if (0 == strncmp("::FFFF:", ip_, 7)) 624 | return ip_ + 7; 625 | else if (0 == strncmp(kWellKnownNat64Prefix, ip_, 9)) 626 | return ip_ + 9; 627 | else 628 | return ip_; 629 | } 630 | 631 | debug_log("invalid ip family:%d, ip:%s", addr_.ss_family, ip_); 632 | return ""; 633 | } 634 | 635 | const char* socket_address::ipv6() const 636 | { 637 | return ip_; 638 | } 639 | 640 | uint16_t socket_address::port() const 641 | { 642 | if (AF_INET == addr_.ss_family) 643 | { 644 | return ntohs(_asv4()->sin_port); 645 | } 646 | else if (AF_INET6 == addr_.ss_family) 647 | { 648 | return ntohs(_asv6()->sin6_port); 649 | } 650 | 651 | return 0; 652 | } 653 | 654 | bool socket_address::valid() const 655 | { 656 | return (AF_INET == addr_.ss_family || AF_INET6 == addr_.ss_family); 657 | } 658 | 659 | bool socket_address::valid_server_address(bool _allowloopback, bool _ignore_port) const 660 | { 661 | if (AF_INET == addr_.ss_family) 662 | { 663 | uint32_t hostip = ntohl(_asv4()->sin_addr.s_addr); 664 | return (_ignore_port ? true : 0 != _asv4()->sin_port) 665 | && hostip != INADDR_ANY 666 | && hostip != INADDR_BROADCAST 667 | && hostip != INADDR_NONE 668 | && (_allowloopback ? true : hostip != INADDR_LOOPBACK); 669 | } 670 | else if (AF_INET6 == addr_.ss_family) 671 | { 672 | if (IN6_IS_ADDR_V4MAPPED(&_asv6()->sin6_addr)) 673 | { 674 | uint32_t hostip = ntohl((*(const uint32_t*)(const void*)(&_asv6()->sin6_addr.s6_addr[12]))); 675 | return (_ignore_port ? true : 0 != _asv6()->sin6_port) 676 | && hostip != INADDR_ANY 677 | && hostip != INADDR_BROADCAST 678 | && hostip != INADDR_NONE 679 | && (_allowloopback ? true : hostip != INADDR_LOOPBACK); 680 | } 681 | else 682 | { 683 | //TODO 684 | return true; 685 | } 686 | } 687 | 688 | return false; 689 | } 690 | 691 | bool socket_address::valid_broadcast_address() const 692 | { 693 | if (AF_INET == addr_.ss_family) 694 | { 695 | return 0 != _asv4()->sin_port && INADDR_BROADCAST == ntohl(_asv4()->sin_addr.s_addr); 696 | } 697 | else if (AF_INET6 == addr_.ss_family) 698 | { 699 | return false; 700 | } 701 | return false; 702 | } 703 | 704 | bool socket_address::valid_loopback_ip() const 705 | { 706 | if (AF_INET == addr_.ss_family) 707 | { 708 | return INADDR_LOOPBACK == ntohl(_asv4()->sin_addr.s_addr); 709 | } 710 | else if (AF_INET6 == addr_.ss_family) 711 | { 712 | return false; 713 | } 714 | return false; 715 | } 716 | 717 | bool socket_address::valid_broadcast_ip() const 718 | { 719 | if (AF_INET == addr_.ss_family) 720 | { 721 | return INADDR_BROADCAST == ntohl(_asv4()->sin_addr.s_addr); 722 | } 723 | else if (AF_INET6 == addr_.ss_family) 724 | { 725 | return false; 726 | } 727 | return false; 728 | } 729 | 730 | bool socket_address::isv4mapped_address() const 731 | { 732 | if (AF_INET6 == addr_.ss_family) 733 | { 734 | return IN6_IS_ADDR_V4MAPPED(&(_asv6()->sin6_addr)); 735 | } 736 | return false; 737 | } 738 | 739 | bool socket_address::isv6() const 740 | { 741 | return AF_INET6 == addr_.ss_family && !isv4mapped_address(); 742 | } 743 | 744 | bool socket_address::isv4() const 745 | { 746 | return AF_INET == addr_.ss_family; 747 | } 748 | 749 | socket_address socket_address::getsockname(SOCKET _sock) 750 | { 751 | struct sockaddr_storage addr = {0}; 752 | socklen_t addr_len = sizeof(addr); 753 | 754 | if (0 == ::getsockname(_sock, (sockaddr*)&addr, &addr_len)) 755 | { 756 | if (AF_INET == addr.ss_family) 757 | { 758 | return socket_address((const sockaddr_in&)addr); 759 | } 760 | else if (AF_INET6 == addr.ss_family) 761 | { 762 | return socket_address((const sockaddr_in6&)addr); 763 | } 764 | } 765 | 766 | return socket_address("0.0.0.0", 0); 767 | } 768 | 769 | socket_address socket_address::getpeername(SOCKET _sock) 770 | { 771 | struct sockaddr_storage addr = {0}; 772 | socklen_t addr_len = sizeof(addr); 773 | 774 | if (0 == ::getpeername(_sock, (sockaddr*)&addr, &addr_len)) 775 | { 776 | if (AF_INET == addr.ss_family) 777 | { 778 | return socket_address((const sockaddr_in&)addr); 779 | } 780 | else if (AF_INET6 == addr.ss_family) 781 | { 782 | return socket_address((const sockaddr_in6&)addr); 783 | } 784 | else 785 | { 786 | debug_log("invalid famiray %d", addr.ss_family); 787 | } 788 | } 789 | 790 | return socket_address("0.0.0.0", 0); 791 | } 792 | 793 | const sockaddr_in* socket_address::_asv4() const 794 | { 795 | return reinterpret_cast(&addr_); 796 | } 797 | 798 | const sockaddr_in6* socket_address::_asv6() const 799 | { 800 | return reinterpret_cast(&addr_); 801 | } 802 | --------------------------------------------------------------------------------