//HTTP CONNECT request exchange process bool __fastcall HTTP_CONNECTRequest( SOCKET_DATA *HTTPSocketData, fd_set *ReadFDS, fd_set *WriteFDS, timeval *Timeout, char *OriginalRecv, const size_t RecvSize) { //Initialization memset(OriginalRecv, 0, RecvSize); std::string HTTPString; HTTPString.append("CONNECT "); HTTPString.append(*Parameter.HTTP_TargetDomain); HTTPString.append(" HTTP/"); HTTPString.append(*Parameter.HTTP_Version); HTTPString.append("\r\nHost: "); HTTPString.append(*Parameter.HTTP_TargetDomain); HTTPString.append("\r\n"); if (Parameter.HTTP_HeaderField != nullptr && !Parameter.HTTP_HeaderField->empty()) HTTPString.append(*Parameter.HTTP_HeaderField); if (Parameter.HTTP_ProxyAuthorization != nullptr && !Parameter.HTTP_ProxyAuthorization->empty()) HTTPString.append(*Parameter.HTTP_ProxyAuthorization); HTTPString.append("\r\n"); //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 //TCP connecting SSIZE_T RecvLen = SocketConnecting(IPPROTO_TCP, HTTPSocketData->Socket, (PSOCKADDR)&HTTPSocketData->SockAddr, HTTPSocketData->AddrLen, HTTPString.c_str(), HTTPString.length()); if (RecvLen == EXIT_FAILURE) { PrintError(LOG_LEVEL_3, LOG_ERROR_NETWORK, L"HTTP connecting error", 0, nullptr, 0); return false; } //HTTP CONNECT request exchange else if (RecvLen >= (SSIZE_T)DNS_PACKET_MINSIZE) { RecvLen = ProxySocketSelecting(HTTPSocketData->Socket, ReadFDS, WriteFDS, Timeout, nullptr, 0, OriginalRecv, RecvSize, HTTP_RESPONSE_MINSIZE, nullptr); } else { RecvLen = ProxySocketSelecting(HTTPSocketData->Socket, ReadFDS, WriteFDS, Timeout, HTTPString.c_str(), HTTPString.length(), OriginalRecv, RecvSize, HTTP_RESPONSE_MINSIZE, nullptr); } if (RecvLen < (SSIZE_T)HTTP_RESPONSE_MINSIZE) { PrintError(LOG_LEVEL_3, LOG_ERROR_NETWORK, L"HTTP request error", 0, nullptr, 0); return false; } else { OriginalRecv[RecvSize - 1U] = 0; HTTPString.clear(); HTTPString = OriginalRecv; } //HTTP CONNECT response check if (HTTPString.find("\r\n") == std::string::npos || HTTPString.find("HTTP/") == std::string::npos) { PrintError(LOG_LEVEL_3, LOG_ERROR_HTTP, L"HTTP server response error", 0, nullptr, 0); return false; } else if (HTTPString.find(" 200 ") == std::string::npos || HTTPString.find(" 200 ") >= HTTPString.find("\r\n")) //Not HTTP status code 200: OK { std::wstring wErrBuffer; HTTPString.erase(HTTPString.find("\r\n"), HTTPString.length() - HTTPString.find("\r\n")); MBSToWCSString(HTTPString.c_str(), HTTPString.length(), wErrBuffer); PrintError(LOG_LEVEL_3, LOG_ERROR_HTTP, wErrBuffer.c_str(), 0, nullptr, 0); return false; } return true; }
int wmain(int argc, wchar_t* argv[]) { //Windows XP with SP3 support #if (defined(PLATFORM_WIN32) && !defined(PLATFORM_WIN64)) GetFunctionPointer(FUNCTION_GETTICKCOUNT64); GetFunctionPointer(FUNCTION_INET_NTOP); #endif #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) int main(int argc, char *argv[]) { #endif //Get commands. if (argc > 0) { if (!ReadCommand(argc, argv)) return EXIT_SUCCESS; } else { return EXIT_FAILURE; } //Read configuration file and WinPcap or LibPcap initialization. if (!ReadParameter()) { WSACleanup(); return EXIT_FAILURE; } //Mark Local DNS address to PTR Records. std::thread NetworkInformationMonitorThread(NetworkInformationMonitor); NetworkInformationMonitorThread.detach(); //Read IPFilter and Hosts. if (Parameter.OperationMode == LISTEN_MODE_CUSTOM || Parameter.BlacklistCheck || Parameter.LocalRouting) { std::thread IPFilterThread(ReadIPFilter); IPFilterThread.detach(); } std::thread HostsThread(ReadHosts); HostsThread.detach(); //DNSCurve initialization #if defined(ENABLE_LIBSODIUM) if (Parameter.DNSCurve && DNSCurveParameter.IsEncryption) { randombytes_set_implementation(&randombytes_salsa20_implementation); randombytes_stir(); DNSCurveInit(); } #endif #if defined(PLATFORM_WIN) //Service initialization and start service. SERVICE_TABLE_ENTRYW ServiceTable[] = {{DEFAULT_LOCAL_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONW)ServiceMain}, {nullptr, nullptr}}; if (!StartServiceCtrlDispatcherW(ServiceTable)) { Parameter.Console = true; wprintf_s(L"System Error: Service start error, error code is %lu.\n", GetLastError()); wprintf_s(L"System Error: Program will continue to run in console mode.\n"); wprintf_s(L"Please ignore those error messages if you want to run in console mode.\n"); //Handle the system signal and start all monitors. SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); MonitorInit(); } #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) MonitorInit(); #endif WSACleanup(); return EXIT_SUCCESS; } //Read commands from main program #if defined(PLATFORM_WIN) bool __fastcall ReadCommand(int argc, wchar_t* argv[]) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) bool ReadCommand(int argc, char *argv[]) #endif { //Path initialization #if defined(PLATFORM_WIN) if (!FileNameInit(argv[0])) return false; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) std::shared_ptr<char> FileName(new char[PATH_MAX + 1U]()); memset(FileName.get(), 0, PATH_MAX + 1U); if (getcwd(FileName.get(), PATH_MAX) == nullptr) { wprintf(L"Path initialization error.\n"); return false; } if (!FileNameInit(FileName.get())) return false; FileName.reset(); #endif #if defined(PLATFORM_WIN) //Winsock initialization std::shared_ptr<WSAData> WSAInitialization(new WSAData()); if (WSAStartup(MAKEWORD(WINSOCK_VERSION_HIGH, WINSOCK_VERSION_LOW), WSAInitialization.get()) != 0 || LOBYTE(WSAInitialization->wVersion) != WINSOCK_VERSION_LOW || HIBYTE(WSAInitialization->wVersion) != WINSOCK_VERSION_HIGH) { wprintf_s(L"Winsock initialization error, error code is %d.\n", WSAGetLastError()); PrintError(LOG_ERROR_NETWORK, L"Winsock initialization error", WSAGetLastError(), nullptr, 0); WSACleanup(); return false; } //Read commands. std::wstring Commands; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) std::string Commands; #endif for (size_t Index = 1U;(SSIZE_T)Index < argc;++Index) { Commands = argv[Index]; //Flush DNS Cache from user. if (Commands == COMMAND_FLUSH_DNS) { #if defined(PLATFORM_WIN) FlushDNSMailSlotSender(); #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) FlushDNSFIFOSender(); #endif WSACleanup(); return false; } //Windows Firewall Test in first start. #if defined(PLATFORM_WIN) else if (Commands == COMMAND_FIREWALL_TEST) { if (!FirewallTest(AF_INET6) && !FirewallTest(AF_INET)) { wprintf_s(L"Windows Firewall Test error.\n"); PrintError(LOG_ERROR_NETWORK, L"Windows Firewall Test error", WSAGetLastError(), nullptr, 0); } WSACleanup(); return false; } #endif //Set system daemon. #if defined(PLATFORM_LINUX) else if (Commands == COMMAND_DISABLE_DAEMON) { Parameter.Daemon = false; } #endif //Print current version. else if (Commands == COMMAND_LONG_PRINT_VERSION || Commands == COMMAND_SHORT_PRINT_VERSION) { wprintf_s(L"Pcap_DNSProxy "); wprintf_s(FULL_VERSION); wprintf_s(L"\n"); WSACleanup(); return false; } //Print help messages. else if (Commands == COMMAND_LONG_HELP || Commands == COMMAND_SHORT_HELP) { wprintf_s(L"Usage: Please see ReadMe... files in Documents folder.\n"); WSACleanup(); return false; } //Set working directory from commands. else if (Commands == COMMAND_LONG_SET_PATH || Commands == COMMAND_SHORT_SET_PATH) { //Commands check if ((SSIZE_T)Index + 1 >= argc) { wprintf_s(L"Commands error.\n"); PrintError(LOG_ERROR_SYSTEM, L"Commands error", 0, nullptr, 0); WSACleanup(); return false; } else { ++Index; Commands = argv[Index]; //Path check. if (Commands.length() > MAX_PATH) { wprintf_s(L"Commands error.\n"); PrintError(LOG_ERROR_SYSTEM, L"Commands error", 0, nullptr, 0); WSACleanup(); return false; } else { if (!FileNameInit(Commands.c_str())) return false; } } } } //Set system daemon. #if defined(PLATFORM_LINUX) if (Parameter.Daemon && daemon(0, 0) == RETURN_ERROR) { PrintError(LOG_ERROR_SYSTEM, L"Set system daemon error", 0, nullptr, 0); return false; } #endif return true; } //Get path of program from the main function parameter and Winsock initialization #if defined(PLATFORM_WIN) bool __fastcall FileNameInit(const wchar_t *OriginalPath) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) bool FileNameInit(const char *OriginalPath) #endif { //Path process #if defined(PLATFORM_WIN) Parameter.Path_Global->clear(); Parameter.Path_Global->push_back(OriginalPath); Parameter.Path_Global->front().erase(Parameter.Path_Global->front().rfind(L"\\") + 1U); for (size_t Index = 0;Index < Parameter.Path_Global->front().length();++Index) { if ((Parameter.Path_Global->front()).at(Index) == L'\\') { Parameter.Path_Global->front().insert(Index, L"\\"); ++Index; } } #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) Parameter.sPath_Global->clear(); Parameter.sPath_Global->push_back(OriginalPath); Parameter.sPath_Global->front().append("/"); std::wstring StringTemp; MBSToWCSString(StringTemp, OriginalPath); StringTemp.append(L"/"); Parameter.Path_Global->clear(); Parameter.Path_Global->push_back(StringTemp); StringTemp.clear(); #endif //Get path of error/running status log file and mark start time. Parameter.Path_ErrorLog->clear(); *Parameter.Path_ErrorLog = Parameter.Path_Global->front(); Parameter.Path_ErrorLog->append(L"Error.log"); #if (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) Parameter.sPath_ErrorLog->clear(); *Parameter.sPath_ErrorLog = Parameter.sPath_Global->front(); Parameter.sPath_ErrorLog->append("Error.log"); #endif Parameter.PrintError = true; time(&StartTime); return true; }
int wmain( int argc, wchar_t* argv[]) { #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) int main( int argc, char *argv[]) { #endif //Get commands. if (argc > 0) { if (!ReadCommand(argc, argv)) return EXIT_SUCCESS; } else { return EXIT_FAILURE; } //Read configuration file. if (!ReadParameter(true)) return EXIT_FAILURE; //DNSCurve initialization #if defined(ENABLE_LIBSODIUM) if (Parameter.DNSCurve) { DNSCurveParameterModificating.SetToMonitorItem(); //Encryption mode initialization if (DNSCurveParameter.IsEncryption) DNSCurveInit(); } #endif //Mark Local DNS address to PTR Records, read Parameter(Monitor mode), IPFilter and Hosts. ParameterModificating.SetToMonitorItem(); std::thread NetworkInformationMonitorThread(std::bind(NetworkInformationMonitor)); NetworkInformationMonitorThread.detach(); std::thread ReadParameterThread(std::bind(ReadParameter, false)); ReadParameterThread.detach(); std::thread ReadHostsThread(std::bind(ReadHosts)); ReadHostsThread.detach(); if (Parameter.OperationMode == LISTEN_MODE_CUSTOM || Parameter.DataCheck_Blacklist || Parameter.LocalRouting) { std::thread ReadIPFilterThread(std::bind(ReadIPFilter)); ReadIPFilterThread.detach(); } #if defined(PLATFORM_WIN) //Service initialization and start service. SERVICE_TABLE_ENTRYW ServiceTable[]{{SYSTEM_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONW)ServiceMain}, {nullptr, nullptr}}; if (!StartServiceCtrlDispatcherW(ServiceTable)) { GlobalRunningStatus.Console = true; auto ErrorCode = GetLastError(); //Print to screen. std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"System Error: Service start error, error code is %lu.\n", ErrorCode); fwprintf_s(stderr, L"System Error: Program will continue to run in console mode.\n"); fwprintf_s(stderr, L"Please ignore these error messages if you want to run in console mode.\n\n"); ScreenMutex.unlock(); //Handle the system signal and start all monitors. SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); MonitorInit(); } #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) MonitorInit(); #endif return EXIT_SUCCESS; } //Read commands from main program #if defined(PLATFORM_WIN) bool __fastcall ReadCommand( int argc, wchar_t *argv[]) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) bool ReadCommand( int argc, char *argv[]) #endif { //Path initialization #if defined(PLATFORM_WIN) if (!FileNameInit(argv[0])) return false; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) char FileName[PATH_MAX + 1U] = {0}; if (getcwd(FileName, PATH_MAX) == nullptr) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf(stderr, L"Path initialization error.\n"); return false; } if (!FileNameInit(FileName)) return false; #endif //Screen output buffer setting if (setvbuf(stderr, NULL, _IONBF, 0) != 0) { auto ErrorCode = errno; std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Screen output buffer setting error, error code is %d.\n", ErrorCode); ScreenLock.unlock(); PrintError(LOG_LEVEL_2, LOG_ERROR_NETWORK, L"Screen output buffer setting error", ErrorCode, nullptr, 0); return false; } //Winsock initialization #if defined(PLATFORM_WIN) WSAData WSAInitialization = {0}; if (WSAStartup(MAKEWORD(WINSOCK_VERSION_HIGH, WINSOCK_VERSION_LOW), &WSAInitialization) != 0 || LOBYTE(WSAInitialization.wVersion) != WINSOCK_VERSION_LOW || HIBYTE(WSAInitialization.wVersion) != WINSOCK_VERSION_HIGH) { auto ErrorCode = WSAGetLastError(); std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Winsock initialization error, error code is %d.\n", ErrorCode); ScreenLock.unlock(); PrintError(LOG_LEVEL_1, LOG_ERROR_NETWORK, L"Winsock initialization error", ErrorCode, nullptr, 0); return false; } else { GlobalRunningStatus.Initialization_WinSock = true; } //Read commands. std::wstring Commands; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) std::string Commands; #endif for (size_t Index = 1U;(SSIZE_T)Index < argc;++Index) { Commands = argv[Index]; //Flush DNS Cache from user. if (Commands == COMMAND_FLUSH_DNS) { #if defined(PLATFORM_WIN) FlushDNSMailSlotSender(); #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) FlushDNSFIFOSender(); #endif return false; } //Windows Firewall Test in first start. #if defined(PLATFORM_WIN) else if (Commands == COMMAND_FIREWALL_TEST) { if (!FirewallTest(AF_INET6) && !FirewallTest(AF_INET)) { auto ErrorCode = WSAGetLastError(); std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Windows Firewall Test error, error code is %d.\n", ErrorCode); ScreenMutex.unlock(); PrintError(LOG_LEVEL_2, LOG_ERROR_NETWORK, L"Windows Firewall Test error", ErrorCode, nullptr, 0); } return false; } #endif //Set system daemon. #if defined(PLATFORM_LINUX) else if (Commands == COMMAND_DISABLE_DAEMON) { GlobalRunningStatus.Daemon = false; } #endif //Print current version. else if (Commands == COMMAND_LONG_PRINT_VERSION || Commands == COMMAND_SHORT_PRINT_VERSION) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Pcap_DNSProxy "); fwprintf_s(stderr, FULL_VERSION); fwprintf_s(stderr, L"\n"); return false; } //Print library version. else if (Commands == COMMAND_LIB_VERSION) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); #if (defined(ENABLE_LIBSODIUM) || defined(ENABLE_PCAP)) std::wstring LibVersion; //LibSodium version #if defined(ENABLE_LIBSODIUM) if (MBSToWCSString(SODIUM_VERSION_STRING, strlen(SODIUM_VERSION_STRING), LibVersion)) fwprintf_s(stderr, L"LibSodium version %ls\n", LibVersion.c_str()); #endif //WinPcap or LibPcap version #if defined(ENABLE_PCAP) if (MBSToWCSString(pcap_lib_version(), strlen(pcap_lib_version()), LibVersion)) fwprintf_s(stderr, L"%ls\n", LibVersion.c_str()); #endif #else fwprintf(stderr, L"No any available libraries.\n"); #endif return false; } //Print help messages. else if (Commands == COMMAND_LONG_HELP || Commands == COMMAND_SHORT_HELP) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Pcap_DNSProxy "); fwprintf_s(stderr, FULL_VERSION); #if defined(PLATFORM_WIN) fwprintf_s(stderr, L"(Windows)\n"); #elif defined(PLATFORM_OPENWRT) fwprintf(stderr, L"(OpenWrt)\n"); #elif defined(PLATFORM_LINUX) fwprintf(stderr, L"(Linux)\n"); #elif defined(PLATFORM_MACX) fwprintf(stderr, L"(Mac)\n"); #endif fwprintf_s(stderr, COPYRIGHT_MESSAGE); fwprintf_s(stderr, L"\nUsage: Please visit ReadMe... files in Documents folder.\n"); fwprintf_s(stderr, L" -v/--version: Print current version on screen.\n"); fwprintf_s(stderr, L" --lib-version: Print current version of libraries on screen.\n"); fwprintf_s(stderr, L" -h/--help: Print help messages on screen.\n"); fwprintf_s(stderr, L" --flush-dns: Flush all DNS cache in program and system immediately.\n"); #if defined(PLATFORM_WIN) fwprintf_s(stderr, L" --first-setup: Test local firewall.\n"); #endif fwprintf_s(stderr, L" -c/--config-file Path: Set path of configuration file.\n"); #if defined(PLATFORM_LINUX) fwprintf(stderr, L" --disable-daemon: Disable daemon mode.\n"); #endif return false; } //Set working directory from commands. else if (Commands == COMMAND_LONG_SET_PATH || Commands == COMMAND_SHORT_SET_PATH) { //Commands check if ((SSIZE_T)Index + 1 >= argc) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf(stderr, L"Commands error.\n"); ScreenMutex.unlock(); PrintError(LOG_LEVEL_1, LOG_ERROR_SYSTEM, L"Commands error", 0, nullptr, 0); return false; } else { ++Index; Commands = argv[Index]; //Path check. if (Commands.length() > MAX_PATH) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Commands error.\n"); ScreenLock.unlock(); PrintError(LOG_LEVEL_1, LOG_ERROR_SYSTEM, L"Commands error", 0, nullptr, 0); return false; } else { if (!FileNameInit(Commands.c_str())) return false; } } } } //Set system daemon. #if defined(PLATFORM_LINUX) if (GlobalRunningStatus.Daemon && daemon(0, 0) == RETURN_ERROR) { PrintError(LOG_LEVEL_2, LOG_ERROR_SYSTEM, L"Set system daemon error", 0, nullptr, 0); return false; } #endif return true; } //Get path of program from the main function parameter and Winsock initialization #if defined(PLATFORM_WIN) bool __fastcall FileNameInit( const wchar_t *OriginalPath) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) bool FileNameInit( const char *OriginalPath) #endif { //Path process #if defined(PLATFORM_WIN) GlobalRunningStatus.Path_Global->clear(); GlobalRunningStatus.Path_Global->push_back(OriginalPath); GlobalRunningStatus.Path_Global->front().erase(GlobalRunningStatus.Path_Global->front().rfind(L"\\") + 1U); for (size_t Index = 0;Index < GlobalRunningStatus.Path_Global->front().length();++Index) { if ((GlobalRunningStatus.Path_Global->front()).at(Index) == L'\\') { GlobalRunningStatus.Path_Global->front().insert(Index, L"\\"); ++Index; } } #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) GlobalRunningStatus.sPath_Global->clear(); GlobalRunningStatus.sPath_Global->push_back(OriginalPath); GlobalRunningStatus.sPath_Global->front().append("/"); std::wstring StringTemp; if (!MBSToWCSString(OriginalPath, PATH_MAX + 1U, StringTemp)) return false; StringTemp.append(L"/"); GlobalRunningStatus.Path_Global->clear(); GlobalRunningStatus.Path_Global->push_back(StringTemp); StringTemp.clear(); #endif //Get path of error/running status log file and mark start time. GlobalRunningStatus.Path_ErrorLog->clear(); *GlobalRunningStatus.Path_ErrorLog = GlobalRunningStatus.Path_Global->front(); GlobalRunningStatus.Path_ErrorLog->append(L"Error.log"); #if (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) GlobalRunningStatus.sPath_ErrorLog->clear(); *GlobalRunningStatus.sPath_ErrorLog = GlobalRunningStatus.sPath_Global->front(); GlobalRunningStatus.sPath_ErrorLog->append("Error.log"); #endif Parameter.PrintLogLevel = DEFAULT_LOG_LEVEL; GlobalRunningStatus.StartupTime = time(nullptr); return true; }
int wmain( _In_ int argc, _In_ wchar_t* argv[]) { #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) int main(int argc, char *argv[]) { #endif #if defined(ENABLE_LIBSODIUM) //Initialization(Part 1) #if defined(PLATFORM_WIN) std::wstring FileName, Command; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) std::string FileName, Command; #endif //Read commands. if (argc < 2) { PrintDescription(); return EXIT_SUCCESS; } else if (argc == 2) //File name only, use default hash function. { //Commands check Command = argv[1U]; CaseConvert(true, Command); if (Command == COMMAND_LONG_PRINT_VERSION || Command == COMMAND_SHORT_PRINT_VERSION) { fwprintf_s(stderr, L"FileHash "); fwprintf_s(stderr, FULL_VERSION); fwprintf_s(stderr, L"\n"); return EXIT_SUCCESS; } else if (Command == COMMAND_LONG_HELP || Command == COMMAND_SHORT_HELP || Command == COMMAND_SIGN_HELP) { PrintDescription(); return EXIT_SUCCESS; } else if (Command == COMMAND_LIB_VERSION) { std::wstring LibVersion; if (MBSToWCSString(SODIUM_VERSION_STRING, strlen(SODIUM_VERSION_STRING), LibVersion)) fwprintf_s(stderr, L"LibSodium version %ls\n", LibVersion.c_str()); return EXIT_SUCCESS; } else { //Mark filename. FileName = argv[1U]; } } else if (argc == 3) //File name with hash function command { Command = argv[1U]; FileName = argv[2U]; //Commands check if (Command.length() < 3U) { fwprintf_s(stderr, L"Commands error.\n"); return EXIT_FAILURE; } else { CaseConvert(true, Command); } //CRC family if (Command.find(HASH_COMMAND_CRC) == 0) { HashFamilyID = HASH_ID_CRC; if (!ReadCommand_CRC(Command)) return EXIT_FAILURE; } //Internet Protocol Checksum else if (Command == HASH_COMMAND_CHECKSUM) { HashFamilyID = HASH_ID_CHECKSUM; } //MD2 else if (Command == HASH_COMMAND_MD2) { HashFamilyID = HASH_ID_MD2; } //MD4 family else if (Command == HASH_COMMAND_MD4) { HashFamilyID = HASH_ID_MD4; } else if (Command == HASH_COMMAND_ED2K) { HashFamilyID = HASH_ID_ED2K; } //MD5 else if (Command == HASH_COMMAND_MD || Command == HASH_COMMAND_MD5) { HashFamilyID = HASH_ID_MD5; } //SHA-1 else if (Command.find(HASH_COMMAND_SHA1) == 0) { HashFamilyID = HASH_ID_SHA1; } //SHA-2 family else if (Command == HASH_COMMAND_SHA2_384 || Command.find(HASH_COMMAND_SHA2_512) == 0 || Command.find(HASH_COMMAND_SHA2) == 0) { HashFamilyID = HASH_ID_SHA2; if (!ReadCommand_SHA2(Command)) return EXIT_FAILURE; } //SHA-3 family else if (Command == HASH_COMMAND_SHA || Command.find(HASH_COMMAND_SHA3) == 0) { HashFamilyID = HASH_ID_SHA3; if (!ReadCommand_SHA3(Command)) return EXIT_FAILURE; } //Commands error else { fwprintf_s(stderr, L"Commands error.\n"); return EXIT_FAILURE; } } else { fwprintf_s(stderr, L"Commands error.\n"); return EXIT_FAILURE; } Command.clear(); Command.shrink_to_fit(); //Open file. FILE *Input = nullptr; #if defined(PLATFORM_WIN) if (_wfopen_s(&Input, FileName.c_str(), L"rb") != 0 || Input == nullptr) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) Input = fopen(FileName.c_str(), "rb"); if (Input == nullptr) #endif { fwprintf_s(stderr, L"Open file error.\n"); return EXIT_FAILURE; } else { if (HashFamilyID == HASH_ID_CRC && !CRC_Hash(Input) || //CRC family HashFamilyID == HASH_ID_CHECKSUM && !Checksum_Hash(Input) || //Internet Protocol Checksum HashFamilyID == HASH_ID_MD2 && !MD2_Hash(Input) || //MD2 (HashFamilyID == HASH_ID_MD4 || HashFamilyID == HASH_ID_ED2K) && !MD4_Hash(Input) || //MD4 family HashFamilyID == HASH_ID_MD5 && !MD5_Hash(Input) || //MD5 HashFamilyID == HASH_ID_SHA1 && !SHA1_Hash(Input) || //SHA-1 HashFamilyID == HASH_ID_SHA2 && !SHA2_Hash(Input) || //SHA-2 family HashFamilyID == HASH_ID_SHA3 && !SHA3_Hash(Input)) //SHA-3 family { fclose(Input); return EXIT_FAILURE; } } fclose(Input); #else #if defined(PLATFORM_WIN) fwprintf_s(stderr, L"LibSodium is disable.\n\n"); system("PAUSE"); #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) fwprintf(stderr, L"LibSodium is disable.\n\n"); #endif #endif return EXIT_SUCCESS; }
//Capture process bool __fastcall CaptureModule(const pcap_if *pDrive, const bool IsCaptureList) { std::string CaptureDevice; //Devices name, address and type check if (pDrive->name == nullptr || pDrive->addresses == nullptr || pDrive->flags == PCAP_IF_LOOPBACK) goto DevicesSkip; //Pcap devices blacklist check if (pDrive->description != nullptr) { CaptureDevice.append(pDrive->description); CaseConvert(false, CaptureDevice); for (auto CaptureIter:*Parameter.PcapDevicesBlacklist) { if (CaptureIter.find(CaptureDevice) != std::string::npos) goto DevicesSkip; } } CaptureDevice.clear(); CaptureDevice.append(pDrive->name); CaseConvert(false, CaptureDevice); for (auto CaptureIter:*Parameter.PcapDevicesBlacklist) { if (CaptureIter.find(CaptureDevice) != std::string::npos) goto DevicesSkip; } //Skip this devices. goto DevicesNotSkip; DevicesSkip: if (IsCaptureList && pDrive->next != nullptr) { std::thread CaptureThread(CaptureModule, pDrive->next, true); CaptureThread.detach(); } return true; DevicesNotSkip: //Initialization(Part 1) pcap_t *DeviceHandle = nullptr; std::shared_ptr<char> Buffer(new char[ORIGINAL_PACKET_MAXSIZE + sizeof(uint16_t)]()); //Reserved 2 bytes for TCP header length. memset(Buffer.get(), 0, ORIGINAL_PACKET_MAXSIZE + sizeof(uint16_t)); CaptureDevice.clear(); CaptureDevice.append(pDrive->name); CaptureDevice.shrink_to_fit(); //Open device #if defined(PLATFORM_WIN) if ((DeviceHandle = pcap_open(pDrive->name, ORIGINAL_PACKET_MAXSIZE, PCAP_OPENFLAG_NOCAPTURE_LOCAL, (int)Parameter.PcapReadingTimeout, nullptr, Buffer.get())) == nullptr) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) if ((DeviceHandle = pcap_open_live(pDrive->name, ORIGINAL_PACKET_MAXSIZE, 0, (int)Parameter.PcapReadingTimeout, Buffer.get())) == nullptr) #endif { std::wstring ErrBuffer; if (MBSToWCSString(ErrBuffer, Buffer.get())) PrintError(LOG_ERROR_PCAP, ErrBuffer.c_str(), 0, nullptr, 0); return false; } //Check device type. uint16_t DeviceType = 0; if (pcap_datalink(DeviceHandle) == DLT_EN10MB || pcap_datalink(DeviceHandle) == DLT_PPP_ETHER || pcap_datalink(DeviceHandle) == DLT_EN3MB) //Ethernet II(Including PPPoE) DeviceType = DLT_EN10MB; else if (pcap_datalink(DeviceHandle) == DLT_APPLE_IP_OVER_IEEE1394) //Apple IEEE 1394 DeviceType = DLT_APPLE_IP_OVER_IEEE1394; if (DeviceType == 0) { pcap_close(DeviceHandle); return false; } //Compile the string into a filter program. std::shared_ptr<bpf_program> BPF_Code(new bpf_program()); memset(BPF_Code.get(), 0, sizeof(bpf_program)); #if defined(PLATFORM_WIN) if (pcap_compile(DeviceHandle, BPF_Code.get(), PcapFilterRules.c_str(), PCAP_COMPILE_OPTIMIZE, (bpf_u_int32)pDrive->addresses->netmask) == PCAP_ERROR) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) if (pcap_compile(DeviceHandle, BPF_Code.get(), PcapFilterRules.c_str(), PCAP_COMPILE_OPTIMIZE, 0) == PCAP_ERROR) #endif { std::wstring ErrBuffer; if (MBSToWCSString(ErrBuffer, pcap_geterr(DeviceHandle))) PrintError(LOG_ERROR_PCAP, ErrBuffer.c_str(), 0, nullptr, 0); pcap_close(DeviceHandle); return false; } //Specify a filter program. if (pcap_setfilter(DeviceHandle, BPF_Code.get()) == PCAP_ERROR) { std::wstring ErrBuffer; if (MBSToWCSString(ErrBuffer, pcap_geterr(DeviceHandle))) PrintError(LOG_ERROR_PCAP, ErrBuffer.c_str(), 0, nullptr, 0); pcap_freecode(BPF_Code.get()); pcap_close(DeviceHandle); return false; } //Start captures with other devices. PcapRunningList.push_back(CaptureDevice); if (IsCaptureList && pDrive->next != nullptr) { std::thread CaptureThread(CaptureModule, pDrive->next, IsCaptureList); CaptureThread.detach(); } //Initialization(Part 2) std::shared_ptr<CAPTURE_HANDLER_PARAM> ParamList(new CAPTURE_HANDLER_PARAM()); memset(ParamList.get(), 0, sizeof(CAPTURE_HANDLER_PARAM)); ParamList->Buffer = Buffer.get(); ParamList->DeviceType = DeviceType; SSIZE_T Result = 0; std::unique_lock<std::mutex> CaptureMutex(CaptureLock); CaptureMutex.unlock(); //Start monitor. for (;;) { Result = pcap_loop(DeviceHandle, PCAP_LOOP_INFINITY, CaptureHandler, (PUCHAR)ParamList.get()); // if (Result == PCAP_ERROR || Result == PCAP_ERROR_BREAK || Result == PCAP_ERROR_NO_SUCH_DEVICE || Result == PCAP_ERROR_RFMON_NOTSUP || Result == PCAP_ERROR_NOT_RFMON) if (Result < EXIT_SUCCESS) { //Delete this capture from devices list. CaptureMutex.lock(); for (auto CaptureIter = PcapRunningList.begin();CaptureIter != PcapRunningList.end();) { if (*CaptureIter == CaptureDevice) { CaptureIter = PcapRunningList.erase(CaptureIter); if (CaptureIter == PcapRunningList.end()) break; } else { ++CaptureIter; } } PcapRunningList.shrink_to_fit(); CaptureMutex.unlock(); //Exit this capture thread. pcap_freecode(BPF_Code.get()); pcap_close(DeviceHandle); return false; } else { Sleep(MONITOR_LOOP_INTERVAL_TIME); continue; } } //Monitor terminated pcap_freecode(BPF_Code.get()); pcap_close(DeviceHandle); PrintError(LOG_ERROR_SYSTEM, L"Capture module Monitor terminated", 0, nullptr, 0); return true; }
//Capture initialization void __fastcall CaptureInit(void) { //Initialization std::shared_ptr<char> ErrBuffer(new char[PCAP_ERRBUF_SIZE]()); memset(ErrBuffer.get(), 0, PCAP_ERRBUF_SIZE); std::wstring wErrBuffer; std::vector<std::string>::iterator CaptureIter; pcap_if *pThedevs = nullptr, *pDrive = nullptr; auto IsErrorFirstPrint = true; std::unique_lock<std::mutex> CaptureMutex(CaptureLock); CaptureMutex.unlock(); //Capture filter initialization CaptureFilterRulesInit(PcapFilterRules); //Capture Monitor for (;;) { //Open all devices. if (pcap_findalldevs(&pThedevs, ErrBuffer.get()) == PCAP_ERROR) { if (MBSToWCSString(wErrBuffer, ErrBuffer.get())) { PrintError(LOG_ERROR_PCAP, wErrBuffer.c_str(), 0, nullptr, 0); wErrBuffer.clear(); } memset(ErrBuffer.get(), 0, PCAP_ERRBUF_SIZE); Sleep(MONITOR_LOOP_INTERVAL_TIME); continue; } //Permissions check and check available network devices. if (pThedevs == nullptr) { if (IsErrorFirstPrint) IsErrorFirstPrint = false; else PrintError(LOG_ERROR_PCAP, L"Insufficient privileges or not any available network devices", 0, nullptr, 0); Sleep(MONITOR_LOOP_INTERVAL_TIME); continue; } else { //Mark captures. if (PcapRunningList.empty()) { std::thread CaptureThread(CaptureModule, pThedevs, true); CaptureThread.detach(); } else { pDrive = pThedevs; //Scan all devices. while (pDrive != nullptr) { CaptureMutex.lock(); for (CaptureIter = PcapRunningList.begin();CaptureIter != PcapRunningList.end();++CaptureIter) { if (*CaptureIter == pDrive->name) { break; } else if (CaptureIter + 1U == PcapRunningList.end()) { std::thread CaptureThread(CaptureModule, pDrive, false); CaptureThread.detach(); break; } } CaptureMutex.unlock(); pDrive = pDrive->next; } } } Sleep(MONITOR_LOOP_INTERVAL_TIME); pcap_freealldevs(pThedevs); } //Monitor terminated PrintError(LOG_ERROR_SYSTEM, L"Capture module Monitor terminated", 0, nullptr, 0); return; }