//Transmission and reception of SOCKS protocol(UDP) size_t __fastcall SOCKSUDPRequest( const char *OriginalSend, const size_t SendSize, char *OriginalRecv, const size_t RecvSize) { //Initialization std::shared_ptr<char> SendBuffer(new char[LARGE_PACKET_MAXSIZE]()); memset(SendBuffer.get(), 0, LARGE_PACKET_MAXSIZE); SOCKET_DATA TCPSocketData = {0}, LocalSocketData = {0}, UDPSocketData = {0}; memset(OriginalRecv, 0, RecvSize); //Socket initialization if (Parameter.SOCKS_Address_IPv6.Storage.ss_family > 0 && //IPv6 (Parameter.SOCKS_Protocol_Network == REQUEST_MODE_NETWORK_BOTH && GlobalRunningStatus.GatewayAvailable_IPv6 || //Auto select Parameter.SOCKS_Protocol_Network == REQUEST_MODE_IPV6 || //IPv6 Parameter.SOCKS_Protocol_Network == REQUEST_MODE_IPV4 && Parameter.SOCKS_Address_IPv4.Storage.ss_family == 0)) //Non-IPv4 { if (!Parameter.SOCKS_UDP_NoHandshake) { //TCP process TCPSocketData.SockAddr.ss_family = AF_INET6; ((PSOCKADDR_IN6)&TCPSocketData.SockAddr)->sin6_addr = Parameter.SOCKS_Address_IPv6.IPv6.sin6_addr; ((PSOCKADDR_IN6)&TCPSocketData.SockAddr)->sin6_port = Parameter.SOCKS_Address_IPv6.IPv6.sin6_port; TCPSocketData.AddrLen = sizeof(sockaddr_in6); TCPSocketData.Socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); //Local process LocalSocketData.SockAddr.ss_family = AF_INET6; LocalSocketData.AddrLen = sizeof(sockaddr_in6); } //UDP process UDPSocketData.SockAddr.ss_family = AF_INET6; ((PSOCKADDR_IN6)&UDPSocketData.SockAddr)->sin6_addr = Parameter.SOCKS_Address_IPv6.IPv6.sin6_addr; if (Parameter.SOCKS_UDP_NoHandshake) ((PSOCKADDR_IN6)&UDPSocketData.SockAddr)->sin6_port = Parameter.SOCKS_Address_IPv6.IPv6.sin6_port; UDPSocketData.AddrLen = sizeof(sockaddr_in6); UDPSocketData.Socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); } else if (Parameter.SOCKS_Address_IPv4.Storage.ss_family > 0 && //IPv4 (Parameter.SOCKS_Protocol_Network == REQUEST_MODE_NETWORK_BOTH && GlobalRunningStatus.GatewayAvailable_IPv4 || //Auto select Parameter.SOCKS_Protocol_Network == REQUEST_MODE_IPV4 || //IPv4 Parameter.SOCKS_Protocol_Network == REQUEST_MODE_IPV6 && Parameter.SOCKS_Address_IPv6.Storage.ss_family == 0)) //Non-IPv6 { if (!Parameter.SOCKS_UDP_NoHandshake) { //TCP process TCPSocketData.SockAddr.ss_family = AF_INET; ((PSOCKADDR_IN)&TCPSocketData.SockAddr)->sin_addr = Parameter.SOCKS_Address_IPv4.IPv4.sin_addr; ((PSOCKADDR_IN)&TCPSocketData.SockAddr)->sin_port = Parameter.SOCKS_Address_IPv4.IPv4.sin_port; TCPSocketData.AddrLen = sizeof(sockaddr_in); TCPSocketData.Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Local process LocalSocketData.SockAddr.ss_family = AF_INET; LocalSocketData.AddrLen = sizeof(sockaddr_in); } //UDP process UDPSocketData.SockAddr.ss_family = AF_INET; ((PSOCKADDR_IN)&UDPSocketData.SockAddr)->sin_addr = Parameter.SOCKS_Address_IPv4.IPv4.sin_addr; if (Parameter.SOCKS_UDP_NoHandshake) ((PSOCKADDR_IN)&UDPSocketData.SockAddr)->sin_port = Parameter.SOCKS_Address_IPv4.IPv4.sin_port; UDPSocketData.AddrLen = sizeof(sockaddr_in); UDPSocketData.Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); } else { return EXIT_FAILURE; } //Socket check and Hop Limits setting if (!Parameter.SOCKS_UDP_NoHandshake && !SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_INVALID_CHECK, false, nullptr) || TCPSocketData.SockAddr.ss_family == AF_INET6 && !SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_HOP_LIMITS_IPV6, false, nullptr) || TCPSocketData.SockAddr.ss_family == AF_INET && (!SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_HOP_LIMITS_IPV4, false, nullptr) || !SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_DO_NOT_FRAGMENT, true, nullptr)) || !SocketSetting(UDPSocketData.Socket, SOCKET_SETTING_INVALID_CHECK, false, nullptr) || UDPSocketData.SockAddr.ss_family == AF_INET6 && !SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_HOP_LIMITS_IPV6, false, nullptr) || UDPSocketData.SockAddr.ss_family == AF_INET && (!SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_HOP_LIMITS_IPV4, false, nullptr) || !SocketSetting(UDPSocketData.Socket, SOCKET_SETTING_DO_NOT_FRAGMENT, true, nullptr))) { closesocket(UDPSocketData.Socket); if (!Parameter.SOCKS_UDP_NoHandshake) closesocket(TCPSocketData.Socket); PrintError(LOG_LEVEL_2, LOG_ERROR_NETWORK, L"SOCKS socket initialization error", 0, nullptr, 0); return EXIT_FAILURE; } //Non-blocking mode setting if (!Parameter.SOCKS_UDP_NoHandshake && !SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_NON_BLOCKING_MODE, true, nullptr) || !SocketSetting(UDPSocketData.Socket, SOCKET_SETTING_NON_BLOCKING_MODE, true, nullptr)) { closesocket(UDPSocketData.Socket); if (!Parameter.SOCKS_UDP_NoHandshake) closesocket(TCPSocketData.Socket); return EXIT_FAILURE; } //Selecting structure setting fd_set ReadFDS = {0}, WriteFDS = {0}; timeval Timeout = {0}; //UDP transmission of standard SOCKS protocol must connect with TCP to server at first. if (!Parameter.SOCKS_UDP_NoHandshake) { //Selection exchange process if (!SOCKSSelectionExchange(&TCPSocketData, &ReadFDS, &WriteFDS, &Timeout, SendBuffer.get(), OriginalRecv, RecvSize)) { shutdown(UDPSocketData.Socket, SD_BOTH); shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(UDPSocketData.Socket); closesocket(TCPSocketData.Socket); return EXIT_FAILURE; } else { memset(SendBuffer.get(), 0, LARGE_PACKET_MAXSIZE); } //UDP connecting and get UDP socket infomation. if (SocketConnecting(IPPROTO_UDP, UDPSocketData.Socket, (PSOCKADDR)&UDPSocketData.SockAddr, UDPSocketData.AddrLen, nullptr, 0) == EXIT_FAILURE || getsockname(UDPSocketData.Socket, (PSOCKADDR)&LocalSocketData.SockAddr, &LocalSocketData.AddrLen) == SOCKET_ERROR) { shutdown(UDPSocketData.Socket, SD_BOTH); shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(UDPSocketData.Socket); closesocket(TCPSocketData.Socket); PrintError(LOG_LEVEL_3, LOG_ERROR_NETWORK, L"SOCKS connecting error", 0, nullptr, 0); return EXIT_FAILURE; } //Client command request process if (!SOCKSClientCommandRequest(IPPROTO_UDP, TCPSocketData.Socket, &ReadFDS, &WriteFDS, &Timeout, SendBuffer.get(), OriginalRecv, RecvSize, &LocalSocketData)) { shutdown(UDPSocketData.Socket, SD_BOTH); shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(UDPSocketData.Socket); closesocket(TCPSocketData.Socket); return EXIT_FAILURE; } else { memset(SendBuffer.get(), 0, LARGE_PACKET_MAXSIZE); //Copy network infomation from server message. if (UDPSocketData.SockAddr.ss_family == AF_INET6) ((PSOCKADDR_IN6)&UDPSocketData.SockAddr)->sin6_port = ((PSOCKADDR_IN6)&LocalSocketData.SockAddr)->sin6_port; else ((PSOCKADDR_IN)&UDPSocketData.SockAddr)->sin_port = ((PSOCKADDR_IN)&LocalSocketData.SockAddr)->sin_port; } } //UDP connecting again if (SocketConnecting(IPPROTO_UDP, UDPSocketData.Socket, (PSOCKADDR)&UDPSocketData.SockAddr, UDPSocketData.AddrLen, nullptr, 0) == EXIT_FAILURE) { if (!Parameter.SOCKS_UDP_NoHandshake) { shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(TCPSocketData.Socket); } PrintError(LOG_LEVEL_3, LOG_ERROR_NETWORK, L"SOCKS connecting error", 0, nullptr, 0); return EXIT_FAILURE; } //SOCKS UDP relay header SSIZE_T RecvLen = sizeof(socks_udp_relay_request); void *SOCKS_Pointer = SendBuffer.get(); if (Parameter.SOCKS_TargetServer.Storage.ss_family == AF_INET6) //IPv6 { ((psocks_udp_relay_request)SOCKS_Pointer)->Address_Type = SOCKS5_ADDRESS_IPV6; SOCKS_Pointer = SendBuffer.get() + RecvLen; RecvLen += (SSIZE_T)sizeof(in6_addr); *(in6_addr *)SOCKS_Pointer = Parameter.SOCKS_TargetServer.IPv6.sin6_addr; SOCKS_Pointer = SendBuffer.get() + RecvLen; RecvLen += (SSIZE_T)sizeof(uint16_t); *(uint16_t *)SOCKS_Pointer = Parameter.SOCKS_TargetServer.IPv6.sin6_port; } else if (Parameter.SOCKS_TargetServer.Storage.ss_family == AF_INET) //IPv4 { ((psocks_udp_relay_request)SOCKS_Pointer)->Address_Type = SOCKS5_ADDRESS_IPV4; SOCKS_Pointer = SendBuffer.get() + RecvLen; RecvLen += (SSIZE_T)sizeof(in_addr); *(in_addr *)SOCKS_Pointer = Parameter.SOCKS_TargetServer.IPv4.sin_addr; SOCKS_Pointer = SendBuffer.get() + RecvLen; RecvLen += (SSIZE_T)sizeof(uint16_t); *(uint16_t *)SOCKS_Pointer = Parameter.SOCKS_TargetServer.IPv4.sin_port; } else if (Parameter.SOCKS_TargetDomain != nullptr && !Parameter.SOCKS_TargetDomain->empty()) //Damain { ((psocks_udp_relay_request)SOCKS_Pointer)->Address_Type = SOCKS5_ADDRESS_DOMAIN; SOCKS_Pointer = SendBuffer.get() + RecvLen; RecvLen += (SSIZE_T)sizeof(uint8_t); *(uint8_t *)SOCKS_Pointer = (uint8_t)Parameter.SOCKS_TargetDomain->length(); SOCKS_Pointer = SendBuffer.get() + RecvLen; memcpy_s(SOCKS_Pointer, (SSIZE_T)LARGE_PACKET_MAXSIZE - ((SSIZE_T)sizeof(socks_udp_relay_request) + RecvLen), Parameter.SOCKS_TargetDomain->c_str(), Parameter.SOCKS_TargetDomain->length()); RecvLen += (SSIZE_T)Parameter.SOCKS_TargetDomain->length(); SOCKS_Pointer = SendBuffer.get() + RecvLen; *(uint16_t *)SOCKS_Pointer = Parameter.SOCKS_TargetDomain_Port; RecvLen += (SSIZE_T)sizeof(uint16_t); } else { shutdown(UDPSocketData.Socket, SD_BOTH); closesocket(UDPSocketData.Socket); if (!Parameter.SOCKS_UDP_NoHandshake) { shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(TCPSocketData.Socket); } return EXIT_FAILURE; } memcpy_s(SendBuffer.get() + RecvLen, RecvSize, OriginalSend, SendSize); RecvLen += (SSIZE_T)SendSize; //Socket timeout setting #if defined(PLATFORM_WIN) Timeout.tv_sec = Parameter.SOCKS_SocketTimeout_Unreliable / SECOND_TO_MILLISECOND; Timeout.tv_usec = Parameter.SOCKS_SocketTimeout_Unreliable % SECOND_TO_MILLISECOND * MICROSECOND_TO_MILLISECOND; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) Timeout.tv_sec = Parameter.SOCKS_SocketTimeout_Reliable.tv_sec; Timeout.tv_usec = Parameter.SOCKS_SocketTimeout_Reliable.tv_usec; #endif //Data exchange RecvLen = ProxySocketSelecting(UDPSocketData.Socket, &ReadFDS, &WriteFDS, &Timeout, SendBuffer.get(), RecvLen, OriginalRecv, RecvSize, sizeof(socks_udp_relay_request) + DNS_PACKET_MINSIZE, nullptr); shutdown(UDPSocketData.Socket, SD_BOTH); closesocket(UDPSocketData.Socket); if (!Parameter.SOCKS_UDP_NoHandshake) { shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(TCPSocketData.Socket); } if (RecvLen >= (SSIZE_T)DNS_PACKET_MINSIZE) { SSIZE_T OriginalRecvLen = RecvLen; //Remove SOCKS UDP relay header SOCKS_Pointer = OriginalRecv; if (Parameter.SOCKS_TargetServer.Storage.ss_family == AF_INET6 && //IPv6 ((psocks_udp_relay_request)SOCKS_Pointer)->Address_Type == SOCKS5_ADDRESS_IPV6 && RecvLen >= (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(in6_addr) + sizeof(uint16_t) + DNS_PACKET_MINSIZE) && memcmp((in6_addr *)(OriginalRecv + sizeof(socks_udp_relay_request)), &Parameter.SOCKS_TargetServer.IPv6.sin6_addr, sizeof(in6_addr)) == 0 && *(uint16_t *)(OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(in6_addr)) == Parameter.SOCKS_TargetServer.IPv6.sin6_port) { memmove_s(OriginalRecv, RecvSize, OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(in6_addr) + sizeof(uint16_t), RecvLen - (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(in6_addr) + sizeof(uint16_t))); RecvLen -= sizeof(socks_udp_relay_request) + sizeof(in6_addr) + sizeof(uint16_t); } else if (Parameter.SOCKS_TargetServer.Storage.ss_family == AF_INET && //IPv4 ((psocks_udp_relay_request)SOCKS_Pointer)->Address_Type == SOCKS5_ADDRESS_IPV4 && RecvLen >= (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(in_addr) + sizeof(uint16_t) + DNS_PACKET_MINSIZE) && (*(in_addr *)(OriginalRecv + sizeof(socks_udp_relay_request))).s_addr == Parameter.SOCKS_TargetServer.IPv4.sin_addr.s_addr && *(uint16_t *)(OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(in_addr)) == Parameter.SOCKS_TargetServer.IPv4.sin_port) { memmove_s(OriginalRecv, RecvSize, OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(in_addr) + sizeof(uint16_t), RecvLen - (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(in_addr) + sizeof(uint16_t))); RecvLen -= sizeof(socks_udp_relay_request) + sizeof(in_addr) + sizeof(uint16_t); } else if (Parameter.SOCKS_TargetDomain != nullptr && !Parameter.SOCKS_TargetDomain->empty()) //Domain /* SOCKS server will reply IPv4/IPv6 address of domain. ((psocks_udp_relay_request)SOCKS_Pointer)->Address_Type == SOCKS5_ADDRESS_DOMAIN && RecvLen >= (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(uint8_t) + Parameter.SOCKS_TargetDomain->length() + sizeof(uint16_t) + DNS_PACKET_MINSIZE) && *(uint8_t *)(OriginalRecv + sizeof(socks_udp_relay_request)) == Parameter.SOCKS_TargetDomain->length() && memcmp(OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(uint8_t), Parameter.SOCKS_TargetDomain->c_str(), Parameter.SOCKS_TargetDomain->length()) == 0 && *(uint16_t *)(OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(uint8_t) + Parameter.SOCKS_TargetDomain->length()) == Parameter.SOCKS_TargetDomain_Port) */ { //IPv6 if (((psocks_udp_relay_request)SOCKS_Pointer)->Address_Type == SOCKS5_ADDRESS_IPV6 && RecvLen >= (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(in6_addr) + sizeof(uint16_t) + DNS_PACKET_MINSIZE)) { memmove_s(OriginalRecv, RecvSize, OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(in6_addr) + sizeof(uint16_t), RecvLen - (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(in6_addr) + sizeof(uint16_t))); RecvLen -= sizeof(socks_udp_relay_request) + sizeof(in6_addr) + sizeof(uint16_t); } //IPv4 else if (((psocks_udp_relay_request)SOCKS_Pointer)->Address_Type == SOCKS5_ADDRESS_IPV4 && RecvLen >= (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(in_addr) + sizeof(uint16_t) + DNS_PACKET_MINSIZE)) { memmove_s(OriginalRecv, RecvSize, OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(in_addr) + sizeof(uint16_t), RecvLen - (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(in_addr) + sizeof(uint16_t))); RecvLen -= sizeof(socks_udp_relay_request) + sizeof(in_addr) + sizeof(uint16_t); } /* SOCKS server will reply IPv4/IPv6 address of domain. memmove_s(OriginalRecv, RecvSize, OriginalRecv + sizeof(socks_udp_relay_request) + sizeof(uint8_t) + Parameter.SOCKS_TargetDomain->length() + sizeof(uint16_t), RecvLen - (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(uint8_t) + Parameter.SOCKS_TargetDomain->length() + sizeof(uint16_t))); return RecvLen - (SSIZE_T)(sizeof(socks_udp_relay_request) + sizeof(uint8_t) + Parameter.SOCKS_TargetDomain->length() + sizeof(uint16_t)); */ } //Server response check if (OriginalRecvLen != RecvLen) { //Responses check RecvLen = CheckResponseData( REQUEST_PROCESS_SOCKS, OriginalRecv, RecvLen, RecvSize, nullptr); if (RecvLen < (SSIZE_T)DNS_PACKET_MINSIZE) return EXIT_FAILURE; //Mark DNS cache. if (Parameter.CacheType > 0) MarkDomainCache(OriginalRecv, RecvLen); return RecvLen; } } return EXIT_FAILURE; }
//Transmission and reception of HTTP protocol size_t __fastcall HTTPRequest( const char *OriginalSend, const size_t SendSize, char *OriginalRecv, const size_t RecvSize) { //Initialization SOCKET_DATA HTTPSocketData = {0}; memset(OriginalRecv, 0, RecvSize); //Socket initialization if (Parameter.HTTP_Address_IPv6.Storage.ss_family > 0 && //IPv6 (Parameter.HTTP_Protocol == REQUEST_MODE_NETWORK_BOTH && GlobalRunningStatus.GatewayAvailable_IPv6 || //Auto select Parameter.HTTP_Protocol == REQUEST_MODE_IPV6 || //IPv6 Parameter.HTTP_Protocol == REQUEST_MODE_IPV4 && Parameter.HTTP_Address_IPv4.Storage.ss_family == 0)) //Non-IPv4 { HTTPSocketData.SockAddr.ss_family = AF_INET6; ((PSOCKADDR_IN6)&HTTPSocketData.SockAddr)->sin6_addr = Parameter.HTTP_Address_IPv6.IPv6.sin6_addr; ((PSOCKADDR_IN6)&HTTPSocketData.SockAddr)->sin6_port = Parameter.HTTP_Address_IPv6.IPv6.sin6_port; HTTPSocketData.AddrLen = sizeof(sockaddr_in6); HTTPSocketData.Socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); } else if (Parameter.HTTP_Address_IPv4.Storage.ss_family > 0 && //IPv4 (Parameter.HTTP_Protocol == REQUEST_MODE_NETWORK_BOTH && GlobalRunningStatus.GatewayAvailable_IPv4 || //Auto select Parameter.HTTP_Protocol == REQUEST_MODE_IPV4 || //IPv4 Parameter.HTTP_Protocol == REQUEST_MODE_IPV6 && Parameter.HTTP_Address_IPv6.Storage.ss_family == 0)) //Non-IPv6 { HTTPSocketData.SockAddr.ss_family = AF_INET; ((PSOCKADDR_IN)&HTTPSocketData.SockAddr)->sin_addr = Parameter.HTTP_Address_IPv4.IPv4.sin_addr; ((PSOCKADDR_IN)&HTTPSocketData.SockAddr)->sin_port = Parameter.HTTP_Address_IPv4.IPv4.sin_port; HTTPSocketData.AddrLen = sizeof(sockaddr_in); HTTPSocketData.Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } else { return EXIT_FAILURE; } //Socket check if (!SocketSetting(HTTPSocketData.Socket, SOCKET_SETTING_INVALID_CHECK, nullptr)) { PrintError(LOG_ERROR_NETWORK, L"HTTP socket initialization error", 0, nullptr, 0); return EXIT_FAILURE; } //Non-blocking mode setting if (!SocketSetting(HTTPSocketData.Socket, SOCKET_SETTING_NON_BLOCKING_MODE, nullptr)) { shutdown(HTTPSocketData.Socket, SD_BOTH); closesocket(HTTPSocketData.Socket); PrintError(LOG_ERROR_NETWORK, L"Socket non-blocking mode setting error", 0, nullptr, 0); return EXIT_FAILURE; } //Selecting structure setting fd_set ReadFDS = {0}, WriteFDS = {0}; timeval Timeout = {0}; //HTTP CONNECT request if (Parameter.HTTP_TargetDomain == nullptr || Parameter.HTTP_Version == nullptr || !HTTP_CONNECTRequest(&HTTPSocketData, &ReadFDS, &WriteFDS, &Timeout, OriginalRecv, RecvSize)) { shutdown(HTTPSocketData.Socket, SD_BOTH); closesocket(HTTPSocketData.Socket); return EXIT_FAILURE; } //Add length of request packet(It must be written in header when transpot with TCP protocol). std::shared_ptr<char> SendBuffer(new char[LARGE_PACKET_MAXSIZE]()); memset(SendBuffer.get(), 0, LARGE_PACKET_MAXSIZE); memcpy_s(SendBuffer.get(), RecvSize, OriginalSend, SendSize); SSIZE_T RecvLen = AddLengthDataToHeader(SendBuffer.get(), SendSize, RecvSize); if (RecvLen < (SSIZE_T)DNS_PACKET_MINSIZE) { shutdown(HTTPSocketData.Socket, SD_BOTH); closesocket(HTTPSocketData.Socket); return EXIT_FAILURE; } //Socket timeout setting #if defined(PLATFORM_WIN) Timeout.tv_sec = Parameter.HTTP_SocketTimeout / SECOND_TO_MILLISECOND; Timeout.tv_usec = Parameter.HTTP_SocketTimeout % SECOND_TO_MILLISECOND * MICROSECOND_TO_MILLISECOND; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) Timeout.tv_sec = Parameter.HTTP_SocketTimeout.tv_sec; Timeout.tv_usec = Parameter.HTTP_SocketTimeout.tv_usec; #endif //Data exchange RecvLen = ProxySocketSelecting(HTTPSocketData.Socket, &ReadFDS, &WriteFDS, &Timeout, SendBuffer.get(), RecvLen, OriginalRecv, RecvSize, DNS_PACKET_MINSIZE, nullptr); shutdown(HTTPSocketData.Socket, SD_BOTH); closesocket(HTTPSocketData.Socket); //Server response check if (RecvLen >= (SSIZE_T)DNS_PACKET_MINSIZE && ntohs(((uint16_t *)OriginalRecv)[0]) >= DNS_PACKET_MINSIZE && RecvLen >= ntohs(((uint16_t *)OriginalRecv)[0])) { RecvLen = ntohs(((uint16_t *)OriginalRecv)[0]); memmove_s(OriginalRecv, RecvSize, OriginalRecv + sizeof(uint16_t), RecvLen); //Responses check RecvLen = CheckResponseData( REQUEST_PROCESS_HTTP, OriginalRecv, RecvLen, RecvSize, nullptr); if (RecvLen < (SSIZE_T)DNS_PACKET_MINSIZE) return EXIT_FAILURE; //Mark DNS cache. if (Parameter.CacheType > 0) MarkDomainCache(OriginalRecv, RecvLen); return RecvLen; } return EXIT_FAILURE; }
//Transmission and reception of SOCKS protocol(TCP) size_t __fastcall SOCKSTCPRequest( const char *OriginalSend, const size_t SendSize, char *OriginalRecv, const size_t RecvSize) { //Initialization std::shared_ptr<char> SendBuffer(new char[LARGE_PACKET_MAXSIZE]()); memset(SendBuffer.get(), 0, LARGE_PACKET_MAXSIZE); SOCKET_DATA TCPSocketData = {0}; memset(OriginalRecv, 0, RecvSize); //Socket initialization if (Parameter.SOCKS_Address_IPv6.Storage.ss_family > 0 && //IPv6 (Parameter.SOCKS_Protocol_Network == REQUEST_MODE_NETWORK_BOTH && GlobalRunningStatus.GatewayAvailable_IPv6 || //Auto select Parameter.SOCKS_Protocol_Network == REQUEST_MODE_IPV6 || //IPv6 Parameter.SOCKS_Protocol_Network == REQUEST_MODE_IPV4 && Parameter.SOCKS_Address_IPv4.Storage.ss_family == 0)) //Non-IPv4 { TCPSocketData.SockAddr.ss_family = AF_INET6; ((PSOCKADDR_IN6)&TCPSocketData.SockAddr)->sin6_addr = Parameter.SOCKS_Address_IPv6.IPv6.sin6_addr; ((PSOCKADDR_IN6)&TCPSocketData.SockAddr)->sin6_port = Parameter.SOCKS_Address_IPv6.IPv6.sin6_port; TCPSocketData.AddrLen = sizeof(sockaddr_in6); TCPSocketData.Socket = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); } else if (Parameter.SOCKS_Address_IPv4.Storage.ss_family > 0 && //IPv4 (Parameter.SOCKS_Protocol_Network == REQUEST_MODE_NETWORK_BOTH && GlobalRunningStatus.GatewayAvailable_IPv4 || //Auto select Parameter.SOCKS_Protocol_Network == REQUEST_MODE_IPV4 || //IPv4 Parameter.SOCKS_Protocol_Network == REQUEST_MODE_IPV6 && Parameter.SOCKS_Address_IPv6.Storage.ss_family == 0)) //Non-IPv6 { TCPSocketData.SockAddr.ss_family = AF_INET; ((PSOCKADDR_IN)&TCPSocketData.SockAddr)->sin_addr = Parameter.SOCKS_Address_IPv4.IPv4.sin_addr; ((PSOCKADDR_IN)&TCPSocketData.SockAddr)->sin_port = Parameter.SOCKS_Address_IPv4.IPv4.sin_port; TCPSocketData.AddrLen = sizeof(sockaddr_in); TCPSocketData.Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); } else { return EXIT_FAILURE; } //Socket check if (!SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_INVALID_CHECK, false, nullptr)) { PrintError(LOG_LEVEL_2, LOG_ERROR_NETWORK, L"SOCKS socket initialization error", 0, nullptr, 0); return EXIT_FAILURE; } //Non-blocking mode setting and Hop Limits setting if (!SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_NON_BLOCKING_MODE, true, nullptr) || TCPSocketData.SockAddr.ss_family == AF_INET6 && !SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_HOP_LIMITS_IPV6, true, nullptr) || TCPSocketData.SockAddr.ss_family == AF_INET && (!SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_HOP_LIMITS_IPV4, true, nullptr) || !SocketSetting(TCPSocketData.Socket, SOCKET_SETTING_DO_NOT_FRAGMENT, true, nullptr))) { shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(TCPSocketData.Socket); return EXIT_FAILURE; } //Selecting structure setting fd_set ReadFDS = {0}, WriteFDS = {0}; timeval Timeout = {0}; //Selection exchange process if (Parameter.SOCKS_Version == SOCKS_VERSION_5) { if (!SOCKSSelectionExchange(&TCPSocketData, &ReadFDS, &WriteFDS, &Timeout, SendBuffer.get(), OriginalRecv, RecvSize)) { shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(TCPSocketData.Socket); return EXIT_FAILURE; } else { memset(SendBuffer.get(), 0, LARGE_PACKET_MAXSIZE); } } //Client command request process if (!SOCKSClientCommandRequest(IPPROTO_TCP, TCPSocketData.Socket, &ReadFDS, &WriteFDS, &Timeout, SendBuffer.get(), OriginalRecv, RecvSize, &TCPSocketData)) { shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(TCPSocketData.Socket); return EXIT_FAILURE; } else { memset(SendBuffer.get(), 0, LARGE_PACKET_MAXSIZE); } //Add length of request packet(It must be written in header when transpot with TCP protocol). memcpy_s(SendBuffer.get(), RecvSize, OriginalSend, SendSize); SSIZE_T RecvLen = AddLengthDataToHeader(SendBuffer.get(), SendSize, RecvSize); if (RecvLen < (SSIZE_T)DNS_PACKET_MINSIZE) { shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(TCPSocketData.Socket); return EXIT_FAILURE; } //Socket timeout setting #if defined(PLATFORM_WIN) Timeout.tv_sec = Parameter.SOCKS_SocketTimeout_Reliable / SECOND_TO_MILLISECOND; Timeout.tv_usec = Parameter.SOCKS_SocketTimeout_Reliable % SECOND_TO_MILLISECOND * MICROSECOND_TO_MILLISECOND; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) Timeout.tv_sec = Parameter.SOCKS_SocketTimeout_Reliable.tv_sec; Timeout.tv_usec = Parameter.SOCKS_SocketTimeout_Reliable.tv_usec; #endif //Data exchange RecvLen = ProxySocketSelecting(TCPSocketData.Socket, &ReadFDS, &WriteFDS, &Timeout, SendBuffer.get(), RecvLen, OriginalRecv, RecvSize, DNS_PACKET_MINSIZE, nullptr); shutdown(TCPSocketData.Socket, SD_BOTH); closesocket(TCPSocketData.Socket); //Server response check if (RecvLen >= (SSIZE_T)DNS_PACKET_MINSIZE && ntohs(((uint16_t *)OriginalRecv)[0]) >= DNS_PACKET_MINSIZE && RecvLen >= ntohs(((uint16_t *)OriginalRecv)[0])) { RecvLen = ntohs(((uint16_t *)OriginalRecv)[0]); memmove_s(OriginalRecv, RecvSize, OriginalRecv + sizeof(uint16_t), RecvLen); //Responses check RecvLen = CheckResponseData( REQUEST_PROCESS_SOCKS, OriginalRecv, RecvLen, RecvSize, nullptr); if (RecvLen < (SSIZE_T)DNS_PACKET_MINSIZE) return EXIT_FAILURE; //Mark DNS cache. if (Parameter.CacheType > 0) MarkDomainCache(OriginalRecv, RecvLen); return RecvLen; } return EXIT_FAILURE; }
//Network Layer(Internet Protocol/IP) process bool __fastcall CaptureNetworkLayer(const char *Buffer, const size_t Length, const uint16_t Protocol) { //Initialization PDNS_SERVER_DATA PacketSource = nullptr; //IPv6 if (Protocol == PPP_IPV6 || Protocol == OSI_L2_IPV6) { auto IPv6_Header = (pipv6_hdr)Buffer; //Validate IPv6 header length. if (ntohs(IPv6_Header->PayloadLength) > Length - sizeof(ipv6_hdr)) return false; //Mark source of packet. if (memcmp(&IPv6_Header->Source, &Parameter.DNSTarget.IPv6.AddressData.IPv6.sin6_addr, sizeof(in6_addr)) == EXIT_SUCCESS) { PacketSource = &Parameter.DNSTarget.IPv6; } else if (memcmp(&IPv6_Header->Source, &Parameter.DNSTarget.Alternate_IPv6.AddressData.IPv6.sin6_addr, sizeof(in6_addr)) == EXIT_SUCCESS) { PacketSource = &Parameter.DNSTarget.Alternate_IPv6; } else if (Parameter.DNSTarget.IPv6_Multi != nullptr) { for (auto &DNSServerDataIter:*Parameter.DNSTarget.IPv6_Multi) { if (memcmp(&IPv6_Header->Source, &DNSServerDataIter.AddressData.IPv6.sin6_addr, sizeof(in6_addr)) == EXIT_SUCCESS) { PacketSource = &DNSServerDataIter; break; } } if (PacketSource == nullptr) return false; } else { return false; } //Get Hop Limits from IPv6 DNS server. //ICMPv6 Protocol if (Parameter.ICMP_Speed > 0 && IPv6_Header->NextHeader == IPPROTO_ICMPV6 && ntohs(IPv6_Header->PayloadLength) >= sizeof(icmpv6_hdr)) { //Validate ICMPv6 checksum. if (GetChecksum_ICMPv6((PUINT8)Buffer, ntohs(IPv6_Header->PayloadLength), IPv6_Header->Destination, IPv6_Header->Source) != CHECKSUM_SUCCESS) return false; //ICMPv6 check if (CaptureCheck_ICMP(Buffer + sizeof(ipv6_hdr), ntohs(IPv6_Header->PayloadLength), AF_INET6)) PacketSource->HopLimitData.HopLimit = IPv6_Header->HopLimit; return true; } //TCP Protocol if (Parameter.HeaderCheck_TCP && IPv6_Header->NextHeader == IPPROTO_TCP && ntohs(IPv6_Header->PayloadLength) >= sizeof(tcp_hdr)) { //Validate TCP checksum. if (GetChecksum_TCPUDP((PUINT8)Buffer, ntohs(IPv6_Header->PayloadLength), AF_INET6, IPPROTO_TCP) != CHECKSUM_SUCCESS) return false; //TCP check if (CaptureCheck_TCP(Buffer + sizeof(ipv6_hdr))) PacketSource->HopLimitData.HopLimit = IPv6_Header->HopLimit; return true; } //UDP Protocol if (IPv6_Header->NextHeader == IPPROTO_UDP && ntohs(IPv6_Header->PayloadLength) >= sizeof(udp_hdr) + DNS_PACKET_MINSIZE) { //Validate UDP checksum. if (GetChecksum_TCPUDP((PUINT8)Buffer, ntohs(IPv6_Header->PayloadLength), AF_INET6, IPPROTO_UDP) != CHECKSUM_SUCCESS) return false; //Port check auto UDP_Header = (pudp_hdr)(Buffer + sizeof(ipv6_hdr)); if (UDP_Header->SrcPort == PacketSource->AddressData.IPv6.sin6_port) { //Domain Test and DNS Options check and get Hop Limit from Domain Test. auto IsMarkHopLimit = false; if (CheckResponseData(Buffer + sizeof(ipv6_hdr) + sizeof(udp_hdr), ntohs(IPv6_Header->PayloadLength) - sizeof(udp_hdr), false, &IsMarkHopLimit) < (SSIZE_T)DNS_PACKET_MINSIZE) return false; if (IsMarkHopLimit) PacketSource->HopLimitData.HopLimit = IPv6_Header->HopLimit; //DNSCurve encryption packet check #if defined(ENABLE_LIBSODIUM) if (Parameter.DNSCurve && //Main(IPv6) (DNSCurveParameter.DNSCurveTarget.IPv6.AddressData.Storage.ss_family > 0 && DNSCurveParameter.DNSCurveTarget.IPv6.ReceiveMagicNumber != nullptr && memcmp(Buffer + sizeof(ipv6_hdr) + sizeof(udp_hdr), DNSCurveParameter.DNSCurveTarget.IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN) == EXIT_SUCCESS || //Alternate(IPv6) DNSCurveParameter.DNSCurveTarget.Alternate_IPv6.AddressData.Storage.ss_family > 0 && DNSCurveParameter.DNSCurveTarget.Alternate_IPv6.ReceiveMagicNumber != nullptr && memcmp(Buffer + sizeof(ipv6_hdr) + sizeof(udp_hdr), DNSCurveParameter.DNSCurveTarget.Alternate_IPv6.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN) == EXIT_SUCCESS)) return false; #endif //Hop Limit must not a ramdom value. if ((size_t)IPv6_Header->HopLimit + (size_t)Parameter.HopLimitFluctuation > (size_t)PacketSource->HopLimitData.HopLimit && (size_t)IPv6_Header->HopLimit < (size_t)PacketSource->HopLimitData.HopLimit + (size_t)Parameter.HopLimitFluctuation) { MatchPortToSend(Buffer + sizeof(ipv6_hdr) + sizeof(udp_hdr), ntohs(IPv6_Header->PayloadLength) - sizeof(udp_hdr), AF_INET6, UDP_Header->DstPort); return true; } } } } //IPv4 else { auto IPv4_Header = (pipv4_hdr)Buffer; //Validate IPv4 header. if (ntohs(IPv4_Header->Length) <= IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES || ntohs(IPv4_Header->Length) > Length || GetChecksum((PUINT16)Buffer, sizeof(ipv4_hdr)) != CHECKSUM_SUCCESS) //Validate IPv4 header checksum. return false; //Mark source of packet. if (IPv4_Header->Source.s_addr == Parameter.DNSTarget.IPv4.AddressData.IPv4.sin_addr.s_addr) { PacketSource = &Parameter.DNSTarget.IPv4; } else if (IPv4_Header->Source.s_addr == Parameter.DNSTarget.Alternate_IPv4.AddressData.IPv4.sin_addr.s_addr) { PacketSource = &Parameter.DNSTarget.Alternate_IPv4; } else if (Parameter.DNSTarget.IPv4_Multi != nullptr) { for (auto &DNSServerDataIter:*Parameter.DNSTarget.IPv4_Multi) { if (IPv4_Header->Source.s_addr == DNSServerDataIter.AddressData.IPv4.sin_addr.s_addr) { PacketSource = &DNSServerDataIter; break; } } if (PacketSource == nullptr) return false; } else { return false; } //IPv4 options check if (Parameter.HeaderCheck_IPv4) { //No standard header length and header ID check if (IPv4_Header->IHL > IPV4_STANDARD_IHL || IPv4_Header->ID == 0) PacketSource->HopLimitData.TTL = IPv4_Header->TTL; //TOS and Flags should not be set. if (IPv4_Header->TOS > 0 || IPv4_Header->Flags > 0) return false; } //Get TTL from IPv4 DNS server. //ICMP Protocol if (Parameter.ICMP_Speed > 0 && IPv4_Header->Protocol == IPPROTO_ICMP && ntohs(IPv4_Header->Length) >= IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES + sizeof(icmp_hdr)) { //Validate ICMP checksum. if (GetChecksum((PUINT16)(Buffer + IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES), ntohs(IPv4_Header->Length) - IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES) != CHECKSUM_SUCCESS) return false; //ICMP Check if (CaptureCheck_ICMP(Buffer + IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES, ntohs(IPv4_Header->Length) - IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES, AF_INET)) PacketSource->HopLimitData.TTL = IPv4_Header->TTL; return true; } //TCP Protocol if (Parameter.HeaderCheck_TCP && IPv4_Header->Protocol == IPPROTO_TCP && ntohs(IPv4_Header->Length) >= IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES + sizeof(tcp_hdr)) { //Validate TCP checksum. if (GetChecksum_TCPUDP((PUINT8)Buffer, ntohs(IPv4_Header->Length) - IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES, AF_INET, IPPROTO_TCP) != CHECKSUM_SUCCESS) return false; //TCP check if (CaptureCheck_TCP(Buffer + IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES)) PacketSource->HopLimitData.TTL = IPv4_Header->TTL; return true; } //UDP Protocol if (IPv4_Header->Protocol == IPPROTO_UDP && ntohs(IPv4_Header->Length) >= IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES + sizeof(udp_hdr) + DNS_PACKET_MINSIZE) { //Validate UDP checksum. if (GetChecksum_TCPUDP((PUINT8)Buffer, ntohs(IPv4_Header->Length) - IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES, AF_INET, IPPROTO_UDP) != CHECKSUM_SUCCESS) return false; //Port check auto UDP_Header = (pudp_hdr)(Buffer + IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES); if (UDP_Header->SrcPort == PacketSource->AddressData.IPv4.sin_port) { //Domain Test and DNS Options check and get TTL from Domain Test. auto IsMarkHopLimit = false; if (CheckResponseData(Buffer + IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES + sizeof(udp_hdr), ntohs(IPv4_Header->Length) - IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES - sizeof(udp_hdr), false, &IsMarkHopLimit) < (SSIZE_T)DNS_PACKET_MINSIZE) return false; if (IsMarkHopLimit) PacketSource->HopLimitData.TTL = IPv4_Header->TTL; //DNSCurve encryption packet check #if defined(ENABLE_LIBSODIUM) if (Parameter.DNSCurve && //Main(IPv4) (DNSCurveParameter.DNSCurveTarget.IPv4.AddressData.Storage.ss_family > 0 && DNSCurveParameter.DNSCurveTarget.IPv4.ReceiveMagicNumber != nullptr && memcmp(Buffer + IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES + sizeof(udp_hdr), DNSCurveParameter.DNSCurveTarget.IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN) == EXIT_SUCCESS || //Alternate(IPv4) DNSCurveParameter.DNSCurveTarget.Alternate_IPv4.AddressData.Storage.ss_family > 0 && DNSCurveParameter.DNSCurveTarget.Alternate_IPv4.ReceiveMagicNumber != nullptr && memcmp(Buffer + IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES + sizeof(udp_hdr), DNSCurveParameter.DNSCurveTarget.Alternate_IPv4.ReceiveMagicNumber, DNSCURVE_MAGIC_QUERY_LEN) == EXIT_SUCCESS)) return false; #endif //TTL must not a ramdom value. if ((size_t)IPv4_Header->TTL + (size_t)Parameter.HopLimitFluctuation > (size_t)PacketSource->HopLimitData.TTL && (size_t)IPv4_Header->TTL < (size_t)PacketSource->HopLimitData.TTL + (size_t)Parameter.HopLimitFluctuation) { MatchPortToSend(Buffer + IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES + sizeof(udp_hdr), ntohs(IPv4_Header->Length) - IPv4_Header->IHL * IPv4_IHL_BYTES_TIMES - sizeof(udp_hdr), AF_INET, UDP_Header->DstPort); return true; } } } } return true; }