5 #include "windows_service.h"
10 main(int argc
, char *argv
[])
12 return dnscrypt_proxy_main(argc
, argv
);
29 #ifndef WINDOWS_SERVICE_NAME
30 # define WINDOWS_SERVICE_NAME "dnscrypt-proxy"
32 #ifndef WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY
33 # define WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY \
34 "SYSTEM\\CurrentControlSet\\Services\\" \
35 WINDOWS_SERVICE_NAME "\\Parameters"
38 static SERVICE_STATUS service_status
;
39 static SERVICE_STATUS_HANDLE service_status_handle
;
40 static _Bool app_is_running_as_a_service
;
43 control_handler(const DWORD wanted_state
)
45 if (wanted_state
== SERVICE_CONTROL_STOP
&&
46 dnscrypt_proxy_loop_break() == 0) {
47 service_status
.dwCurrentState
= SERVICE_STOPPED
;
49 SetServiceStatus(service_status_handle
, &service_status
);
53 cmdline_clone_options(const int argc
, char ** const argv
)
57 if (argc
>= INT_MAX
|| (size_t) argc
>= SIZE_MAX
/ sizeof *argv_new
||
58 (argv_new
= calloc((unsigned int) argc
+ 1U,
59 sizeof *argv_new
)) == NULL
) {
62 memcpy(argv_new
, argv
, (unsigned int) (argc
+ 1U) * sizeof *argv_new
);
68 cmdline_add_option(int * const argc_p
, char *** const argv_p
,
69 const char * const arg
)
74 if (*argc_p
>= INT_MAX
||
75 SIZE_MAX
/ sizeof *argv_new
<= (unsigned int) (*argc_p
+ 2U)) {
78 if ((argv_new
= realloc(*argv_p
, (unsigned int) (*argc_p
+ 2U) *
79 sizeof *argv_new
)) == NULL
) {
82 if ((arg_dup
= strdup(arg
)) == NULL
) {
86 argv_new
[(*argc_p
)++] = arg_dup
;
87 argv_new
[*argc_p
] = NULL
;
89 logger(NULL
, LOG_INFO
, "Adding command-line option: [%s]", arg_dup
);
94 typedef struct WindowsServiceParseMultiSzCb_
{
95 void (*cb
)(struct WindowsServiceParseMultiSzCb_
*, const char *string
);
97 char *** const argv_p
;
99 } WindowsServiceParseMultiSzCb
;
102 windows_service_parse_multi_sz_cb(WindowsServiceParseMultiSzCb
* const cb
,
105 assert(cb
->cb
== windows_service_parse_multi_sz_cb
);
106 *(cb
->err_p
) += cmdline_add_option(cb
->argc_p
, cb
->argv_p
, "--plugin");
107 *(cb
->err_p
) += cmdline_add_option(cb
->argc_p
, cb
->argv_p
, string
);
111 windows_service_parse_multi_sz(WindowsServiceParseMultiSzCb
* const cb
,
112 const char * const multi_sz
,
113 const size_t multi_sz_len
)
115 const char *multi_sz_pnt
= multi_sz
;
118 size_t multi_sz_remaining_len
= multi_sz_len
;
121 while (multi_sz_remaining_len
> (size_t) 0U &&
122 (zero
= memchr(multi_sz_pnt
, 0, multi_sz_remaining_len
)) != NULL
) {
123 if ((len
= (size_t) (zero
- multi_sz_pnt
)) > (size_t) 0U) {
124 cb
->cb(cb
, multi_sz_pnt
);
126 zlen
= len
+ (size_t) 1U;
127 assert(zlen
<= multi_sz_remaining_len
);
128 multi_sz_remaining_len
-= zlen
;
129 multi_sz_pnt
+= zlen
;
135 windows_service_registry_read_multi_sz(const char * const key
,
136 WindowsServiceParseMultiSzCb
* const cb
)
143 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
144 WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY
,
145 (DWORD
) 0, KEY_READ
, &hk
) != ERROR_SUCCESS
) {
148 if (RegQueryValueEx(hk
, key
, 0,
149 &value_type
, NULL
, &value_len
) == ERROR_SUCCESS
&&
150 value_type
== (DWORD
) REG_MULTI_SZ
&&
151 value_len
<= SIZE_MAX
&& value_len
> (DWORD
) 0 &&
152 (value
= malloc((size_t) value_len
)) != NULL
) {
153 if (RegQueryValueEx(hk
, key
, 0,
154 &value_type
, value
, &value_len
) != ERROR_SUCCESS
||
155 value_type
!= (DWORD
) REG_MULTI_SZ
) {
159 assert(value
== NULL
|| value_len
== 0 ||
160 (value_len
> 0 && value
[value_len
- 1] == 0));
166 windows_service_parse_multi_sz(cb
, (const char *) value
,
174 windows_service_registry_read_string(const char * const key
,
175 char ** const value_p
)
183 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
184 WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY
,
185 (DWORD
) 0, KEY_READ
, &hk
) != ERROR_SUCCESS
) {
188 if (RegQueryValueEx(hk
, key
, 0,
189 &value_type
, NULL
, &value_len
) == ERROR_SUCCESS
&&
190 value_type
== (DWORD
) REG_SZ
&&
191 value_len
<= SIZE_MAX
&& value_len
> (DWORD
) 0 &&
192 (value
= malloc((size_t) value_len
)) != NULL
) {
193 if (RegQueryValueEx(hk
, key
, 0,
194 &value_type
, value
, &value_len
) != ERROR_SUCCESS
||
195 value_type
!= (DWORD
) REG_SZ
) {
199 assert(value
== NULL
|| value_len
== 0 ||
200 (value_len
> 0 && value
[value_len
- 1] == 0));
203 *value_p
= (char *) value
;
205 return - (value
== NULL
);
209 windows_service_registry_read_dword(const char * const key
,
210 DWORD
* const value_p
)
214 DWORD value_len
= (DWORD
) sizeof value
;
218 *value_p
= (DWORD
) 0;
219 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
220 WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY
,
221 (DWORD
) 0, KEY_READ
, &hk
) != ERROR_SUCCESS
) {
224 if (RegQueryValueEx(hk
, key
, 0, &value_type
, (void *) &value
, &value_len
)
225 == ERROR_SUCCESS
&& value_type
== (DWORD
) REG_DWORD
) {
235 windows_build_command_line_from_registry(int * const argc_p
,
236 char *** const argv_p
)
238 char dword_string
[sizeof "2147483648"];
243 if ((*argv_p
= cmdline_clone_options(*argc_p
, *argv_p
)) == NULL
) {
246 if (windows_service_registry_read_string
247 ("LocalAddress", &string_value
) == 0) {
248 err
+= cmdline_add_option(argc_p
, argv_p
, "--local-address");
249 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
252 if (windows_service_registry_read_string
253 ("ProviderKey", &string_value
) == 0) {
254 err
+= cmdline_add_option(argc_p
, argv_p
, "--provider-key");
255 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
258 if (windows_service_registry_read_string
259 ("ProviderName", &string_value
) == 0) {
260 err
+= cmdline_add_option(argc_p
, argv_p
, "--provider-name");
261 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
264 if (windows_service_registry_read_string
265 ("ResolverAddress", &string_value
) == 0) {
266 err
+= cmdline_add_option(argc_p
, argv_p
, "--resolver-address");
267 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
270 if (windows_service_registry_read_dword
271 ("EDNSPayloadSize", &dword_value
) == 0) {
272 snprintf(dword_string
, sizeof dword_string
, "%ld", (long) dword_value
);
273 err
+= cmdline_add_option(argc_p
, argv_p
, "--edns-payload-size");
274 err
+= cmdline_add_option(argc_p
, argv_p
, dword_string
);
276 if (windows_service_registry_read_dword
277 ("MaxActiveRequests", &dword_value
) == 0) {
278 snprintf(dword_string
, sizeof dword_string
, "%ld", (long) dword_value
);
279 err
+= cmdline_add_option(argc_p
, argv_p
, "--max-active-requests");
280 err
+= cmdline_add_option(argc_p
, argv_p
, dword_string
);
282 if (windows_service_registry_read_dword
283 ("TCPOnly", &dword_value
) == 0 && dword_value
> (DWORD
) 0) {
284 err
+= cmdline_add_option(argc_p
, argv_p
, "--tcp-only");
286 windows_service_registry_read_multi_sz
287 ("Plugins", & (WindowsServiceParseMultiSzCb
) {
288 .cb
= windows_service_parse_multi_sz_cb
,
300 service_main(DWORD argc_
, LPTSTR
*argv_
)
302 char **argv
= (char **) argv_
;
303 int argc
= (int) argc_
;
305 assert(argc_
< INT_MAX
);
306 if (windows_build_command_line_from_registry(&argc
, &argv
) != 0) {
307 logger_noformat(NULL
, LOG_ERR
,
308 "Unable to build a command line from the registry");
311 memset(&service_status
, 0, sizeof service_status
);
312 service_status
.dwServiceType
= SERVICE_WIN32
;
313 service_status
.dwCurrentState
= SERVICE_START_PENDING
;
314 service_status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
315 service_status_handle
=
316 RegisterServiceCtrlHandler(WINDOWS_SERVICE_NAME
, control_handler
);
317 if (service_status_handle
== 0) {
320 service_status
.dwCurrentState
= SERVICE_RUNNING
;
321 SetServiceStatus(service_status_handle
, &service_status
);
323 dnscrypt_proxy_main(argc
, argv
);
327 windows_main(int argc
, char *argv
[])
329 static SERVICE_TABLE_ENTRY service_table
[2];
332 if ((service_name
= strdup(WINDOWS_SERVICE_NAME
)) == NULL
) {
336 memcpy(service_table
, (SERVICE_TABLE_ENTRY
[2]) {
337 { .lpServiceName
= service_name
, .lpServiceProc
= service_main
},
338 { .lpServiceName
= NULL
, .lpServiceProc
= (void *) NULL
}
339 }, sizeof service_table
);
340 if (StartServiceCtrlDispatcher(service_table
) == 0) {
342 return dnscrypt_proxy_main(argc
, argv
);
344 app_is_running_as_a_service
= 1;
350 windows_service_uninstall(void)
352 SC_HANDLE scm_handle
;
353 SC_HANDLE service_handle
;
356 scm_handle
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
357 if (scm_handle
== NULL
) {
360 service_handle
= OpenService(scm_handle
, WINDOWS_SERVICE_NAME
, DELETE
);
361 if (service_handle
== NULL
) {
362 CloseServiceHandle(scm_handle
);
365 if (DeleteService(service_handle
) == 0) {
368 CloseServiceHandle(service_handle
);
369 CloseServiceHandle(scm_handle
);
375 windows_service_install(const int argc
, const char * const argv
[])
377 char self_path
[MAX_PATH
];
378 SC_HANDLE scm_handle
;
379 SC_HANDLE service_handle
;
383 if (GetModuleFileName(NULL
, self_path
, MAX_PATH
) <= (DWORD
) 0) {
386 scm_handle
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
387 if (scm_handle
== NULL
) {
390 service_handle
= CreateService
391 (scm_handle
, WINDOWS_SERVICE_NAME
,
392 WINDOWS_SERVICE_NAME
, SERVICE_ALL_ACCESS
,
393 SERVICE_WIN32_OWN_PROCESS
, SERVICE_AUTO_START
,
394 SERVICE_ERROR_NORMAL
, self_path
, NULL
, NULL
, NULL
, NULL
, NULL
);
395 if (service_handle
== NULL
) {
396 CloseServiceHandle(scm_handle
);
399 StartService(service_handle
, (DWORD
) 0, NULL
);
400 CloseServiceHandle(service_handle
);
401 CloseServiceHandle(scm_handle
);
407 windows_service_option(const int opt_flag
, const int argc
,
410 if (app_is_running_as_a_service
!= 0) {
414 case WIN_OPTION_INSTALL
:
415 case WIN_OPTION_REINSTALL
:
416 windows_service_uninstall();
417 if (windows_service_install(argc
, argv
) != 0) {
418 logger_noformat(NULL
, LOG_ERR
, "Unable to install the service");
421 logger_noformat(NULL
, LOG_INFO
, "The " WINDOWS_SERVICE_NAME
422 " service has been installed and started");
426 case WIN_OPTION_UNINSTALL
:
427 if (windows_service_uninstall() != 0) {
428 logger_noformat(NULL
, LOG_ERR
, "Unable to uninstall the service");
431 logger_noformat(NULL
, LOG_INFO
, "The " WINDOWS_SERVICE_NAME
432 " service has been removed from this system");
443 main(int argc
, char *argv
[])
445 return windows_main(argc
, argv
);