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(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; }
//The Main function of program int main(int argc, char *argv[]) { #ifdef _DEBUG //Handle the system signal. SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); #endif if (argc > 0) { std::shared_ptr<wchar_t> wPath(new wchar_t[MAX_PATH]()); //Path initialization and Winsock initialization. MultiByteToWideChar(CP_ACP, NULL, argv[0], MBSTOWCS_NULLTERMINATE, wPath.get(), MAX_PATH); if (FileInit(wPath.get()) == EXIT_FAILURE) return EXIT_FAILURE; wPath.reset(); //Windows Firewall Test in first start. if (argc > 1 && strlen(argv[1U]) == strlen("--FirstStart") && memcmp(argv[1], ("--FirstStart"), strlen("--FirstStart")) == 0) { if (FirewallTest(AF_INET6) == EXIT_FAILURE && FirewallTest(AF_INET) == EXIT_FAILURE) { PrintError(WINSOCK_ERROR, L"Windows Firewall Test error", NULL, nullptr, NULL); WSACleanup(); return EXIT_FAILURE; } else { return EXIT_SUCCESS; } } } else { return EXIT_FAILURE; } //Read configuration file and WinPcap initialization. if (Parameter.ReadParameter() == EXIT_FAILURE) { WSACleanup(); return EXIT_FAILURE; } std::thread CaptureInitializationThread(CaptureInit); CaptureInitializationThread.detach(); //Get Localhost DNS PTR Records. std::thread IPv6LocalAddressThread(LocalAddressToPTR, AF_INET6); std::thread IPv4LocalAddressThread(LocalAddressToPTR, AF_INET); IPv6LocalAddressThread.detach(); IPv4LocalAddressThread.detach(); //DNSCurve initialization if (Parameter.DNSCurve && DNSCurveParameter.Encryption) { randombytes_set_implementation(&randombytes_salsa20_implementation); DNSCurveInit(); } //Read IPFilter, start DNS Cache monitor(Timer type) and read Hosts. if (Parameter.FileRefreshTime > 0) { if (Parameter.OperationMode == LISTEN_CUSTOMMODE) { std::thread IPFilterThread(&Configuration::ReadIPFilter, std::ref(Parameter)); IPFilterThread.detach(); } if (Parameter.CacheType != 0) { std::thread DNSCacheTimerThread(DNSCacheTimerMonitor, Parameter.CacheType); DNSCacheTimerThread.detach(); } std::thread HostsThread(&Configuration::ReadHosts, std::ref(Parameter)); HostsThread.detach(); } //Service initialization and start service. SERVICE_TABLE_ENTRYW ServiceTable[] = {{LOCAL_SERVICENAME, (LPSERVICE_MAIN_FUNCTIONW)ServiceMain}, {nullptr, NULL}}; if (!StartServiceCtrlDispatcherW(ServiceTable)) { PrintError(SYSTEM_ERROR, L"Service start error", GetLastError(), nullptr, NULL); WSACleanup(); return EXIT_FAILURE; } WSACleanup(); return EXIT_SUCCESS; }