From 23babdc8facff4cc9528bcace843e79615d2676f Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Wed, 20 Dec 2017 17:03:22 +0300 Subject: [PATCH] Windows Service support. Program can now be started as a Windows Service. No additional arguments needed. Refer to `service_install` and `service_remove` scripts in released zip file. --- README.md | 22 ++------------ goodbyedpi.c | 13 +++++++- goodbyedpi.h | 3 ++ service.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++ service.h | 3 ++ 5 files changed, 103 insertions(+), 21 deletions(-) create mode 100644 service.c create mode 100644 service.h diff --git a/README.md b/README.md index 9905ea2..2675962 100644 --- a/README.md +++ b/README.md @@ -79,26 +79,8 @@ And for x86_64: # How to install as Windows Service -One way is using an [srvstart](http://www.rozanski.org.uk/software) program. -Unpack it to `goodbyedpi` directory and create 3 files: - -*goodbyedpi.ini* -```INI -[GoodByeDPI] -startup=goodbyedpi.exe -shutdown_method=winmessage -auto_restart=n -``` -*srvinstall.bat* -```Batchfile -srvstart install GoodByeDPI -c %CD%\goodbyedpi.ini -``` -*srvremove.bat* -```Batchfile -srvstart remove GoodByeDPI -``` -Run these batch files as Administrator to install/remove service. -Open Windows Services panel to run service or make it start automaticaly. +Use `service_install_russia_blacklist.cmd`, `service_install_russia_blacklist_dnsredir.cmd` and `service_remove.cmd` scripts. +Modify them according to your own needs. # Similar projects diff --git a/goodbyedpi.c b/goodbyedpi.c index a1d6010..63493ed 100644 --- a/goodbyedpi.c +++ b/goodbyedpi.c @@ -11,6 +11,7 @@ #include #include "windivert.h" #include "goodbyedpi.h" +#include "service.h" #include "dnsredir.h" #include "blackwhitelist.h" @@ -52,6 +53,7 @@ } \ } while (0) +static int running_from_service = 0; static HANDLE filters[MAX_FILTERS]; static int filter_num = 0; static const char *http10_redirect_302 = "HTTP/1.0 302 "; @@ -144,7 +146,7 @@ static int deinit(HANDLE handle) { return FALSE; } -static void deinit_all() { +void deinit_all() { for (int i = 0; i < filter_num; i++) { deinit(filters[i]); } @@ -277,6 +279,15 @@ int main(int argc, char *argv[]) { char *hdr_name_addr = NULL, *hdr_value_addr = NULL; int hdr_value_len; + if (!running_from_service && service_register(argc, argv)) { + /* We've been called as a service. Register service + * and exit this thread. main() would be called from + * service.c next time. + */ + running_from_service = 1; + return 0; + } + if (filter_string == NULL) { filter_string = malloc(strlen(filter_string_template) + 1); strcpy(filter_string, filter_string_template); diff --git a/goodbyedpi.h b/goodbyedpi.h index 7d45a82..626e85e 100644 --- a/goodbyedpi.h +++ b/goodbyedpi.h @@ -5,3 +5,6 @@ #else #define debug(...) printf(__VA_ARGS__) #endif + +int main(int argc, char *argv[]); +void deinit_all(); diff --git a/service.c b/service.c new file mode 100644 index 0000000..951f00f --- /dev/null +++ b/service.c @@ -0,0 +1,83 @@ +#include +#include +#include "goodbyedpi.h" +#include "service.h" + +#define SERVICE_NAME "GoodbyeDPI" + +static SERVICE_STATUS ServiceStatus; +static SERVICE_STATUS_HANDLE hStatus; +static int service_argc; +static char **service_argv; + +int service_register(int argc, char *argv[]) +{ + SERVICE_TABLE_ENTRY ServiceTable[] = { + {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main}, + {NULL, NULL} + }; + /* + * Save argc & argv as service_main is called with different + * arguments, which are passed from "start" command, not + * from the program command line. + * We don't need this behaviour. + */ + service_argc = argc; + service_argv = malloc(sizeof(void*) * argc); + for (int i = 0; i < argc; i++) { + service_argv[i] = strdup(argv[i]); + } + return StartServiceCtrlDispatcher(ServiceTable); +} + +void service_main(int argc __attribute__((unused)), + char *argv[] __attribute__((unused))) +{ + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwServiceSpecificExitCode = 0; + ServiceStatus.dwCheckPoint = 1; + ServiceStatus.dwWaitHint = 0; + + hStatus = RegisterServiceCtrlHandler( + SERVICE_NAME, + (LPHANDLER_FUNCTION)service_controlhandler); + if (hStatus == (SERVICE_STATUS_HANDLE)0) + { + // Registering Control Handler failed + return; + } + + SetServiceStatus(hStatus, &ServiceStatus); + + // Calling main with saved argc & argv + main(service_argc, service_argv); + + if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) { + // If terminated with error + ServiceStatus.dwWin32ExitCode = 1; + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus (hStatus, &ServiceStatus); + } + return; +} + +// Control handler function +void service_controlhandler(DWORD request) +{ + switch(request) + { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + deinit_all(); + ServiceStatus.dwWin32ExitCode = 0; + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + default: + break; + } + // Report current status + SetServiceStatus (hStatus, &ServiceStatus); + return; +} diff --git a/service.h b/service.h new file mode 100644 index 0000000..67cd7bb --- /dev/null +++ b/service.h @@ -0,0 +1,3 @@ +int service_register(); +void service_main(int argc, char *argv[]); +void service_controlhandler(DWORD request);