5 #include "dnscrypt_proxy.h"
7 #include "windows_service.h"
12 main(int argc
, char *argv
[])
14 return dnscrypt_proxy_main(argc
, argv
);
31 static SERVICE_STATUS service_status
;
32 static SERVICE_STATUS_HANDLE service_status_handle
;
33 static _Bool app_is_running_as_a_service
;
36 control_handler(const DWORD wanted_state
)
38 if (wanted_state
== SERVICE_CONTROL_STOP
&&
39 dnscrypt_proxy_loop_break() == 0) {
40 service_status
.dwCurrentState
= SERVICE_STOPPED
;
42 SetServiceStatus(service_status_handle
, &service_status
);
46 cmdline_clone_options(const int argc
, char ** const argv
)
50 if (argc
>= INT_MAX
|| (size_t) argc
>= SIZE_MAX
/ sizeof *argv_new
||
51 (argv_new
= calloc((unsigned int) argc
+ 1U,
52 sizeof *argv_new
)) == NULL
) {
55 memcpy(argv_new
, argv
, (unsigned int) (argc
+ 1U) * sizeof *argv_new
);
61 cmdline_add_option(int * const argc_p
, char *** const argv_p
,
62 const char * const arg
)
67 if (*argc_p
>= INT_MAX
||
68 SIZE_MAX
/ sizeof *argv_new
<= (unsigned int) (*argc_p
+ 2U)) {
71 if ((argv_new
= realloc(*argv_p
, (unsigned int) (*argc_p
+ 2U) *
72 sizeof *argv_new
)) == NULL
) {
75 if ((arg_dup
= strdup(arg
)) == NULL
) {
79 argv_new
[(*argc_p
)++] = arg_dup
;
80 argv_new
[*argc_p
] = NULL
;
82 logger(NULL
, LOG_INFO
, "Adding command-line option: [%s]", arg_dup
);
87 typedef struct WindowsServiceParseMultiSzCb_
{
88 void (*cb
)(struct WindowsServiceParseMultiSzCb_
*, const char *string
);
90 char *** const argv_p
;
92 } WindowsServiceParseMultiSzCb
;
95 windows_service_parse_multi_sz_cb(WindowsServiceParseMultiSzCb
* const cb
,
98 assert(cb
->cb
== windows_service_parse_multi_sz_cb
);
99 *(cb
->err_p
) += cmdline_add_option(cb
->argc_p
, cb
->argv_p
, "--plugin");
100 *(cb
->err_p
) += cmdline_add_option(cb
->argc_p
, cb
->argv_p
, string
);
104 windows_service_parse_multi_sz(WindowsServiceParseMultiSzCb
* const cb
,
105 const char * const multi_sz
,
106 const size_t multi_sz_len
)
108 const char *multi_sz_pnt
= multi_sz
;
111 size_t multi_sz_remaining_len
= multi_sz_len
;
114 while (multi_sz_remaining_len
> (size_t) 0U &&
115 (zero
= memchr(multi_sz_pnt
, 0, multi_sz_remaining_len
)) != NULL
) {
116 if ((len
= (size_t) (zero
- multi_sz_pnt
)) > (size_t) 0U) {
117 cb
->cb(cb
, multi_sz_pnt
);
119 zlen
= len
+ (size_t) 1U;
120 assert(zlen
<= multi_sz_remaining_len
);
121 multi_sz_remaining_len
-= zlen
;
122 multi_sz_pnt
+= zlen
;
128 windows_service_registry_read_multi_sz(const char * const key
,
129 WindowsServiceParseMultiSzCb
* const cb
)
136 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
137 WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY
,
138 (DWORD
) 0, KEY_READ
, &hk
) != ERROR_SUCCESS
) {
141 if (RegQueryValueEx(hk
, key
, 0,
142 &value_type
, NULL
, &value_len
) == ERROR_SUCCESS
&&
143 value_type
== (DWORD
) REG_MULTI_SZ
&&
144 value_len
<= SIZE_MAX
&& value_len
> (DWORD
) 0 &&
145 (value
= malloc((size_t) value_len
)) != NULL
) {
146 if (RegQueryValueEx(hk
, key
, 0,
147 &value_type
, value
, &value_len
) != ERROR_SUCCESS
||
148 value_type
!= (DWORD
) REG_MULTI_SZ
) {
152 assert(value
== NULL
|| value_len
== 0 ||
153 (value_len
> 0 && value
[value_len
- 1] == 0));
159 windows_service_parse_multi_sz(cb
, (const char *) value
,
167 windows_service_registry_read_string(const char * const key
,
168 char ** const value_p
)
176 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
177 WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY
,
178 (DWORD
) 0, KEY_READ
, &hk
) != ERROR_SUCCESS
) {
181 if (RegQueryValueEx(hk
, key
, 0,
182 &value_type
, NULL
, &value_len
) == ERROR_SUCCESS
&&
183 value_type
== (DWORD
) REG_SZ
&&
184 value_len
<= SIZE_MAX
&& value_len
> (DWORD
) 0 &&
185 (value
= malloc((size_t) value_len
)) != NULL
) {
186 if (RegQueryValueEx(hk
, key
, 0,
187 &value_type
, value
, &value_len
) != ERROR_SUCCESS
||
188 value_type
!= (DWORD
) REG_SZ
) {
192 assert(value
== NULL
|| value_len
== 0 ||
193 (value_len
> 0 && value
[value_len
- 1] == 0));
196 *value_p
= (char *) value
;
198 return - (value
== NULL
);
202 windows_service_registry_read_dword(const char * const key
,
203 DWORD
* const value_p
)
207 DWORD value_len
= (DWORD
) sizeof value
;
211 *value_p
= (DWORD
) 0;
212 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
,
213 WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY
,
214 (DWORD
) 0, KEY_READ
, &hk
) != ERROR_SUCCESS
) {
217 if (RegQueryValueEx(hk
, key
, 0, &value_type
, (void *) &value
, &value_len
)
218 == ERROR_SUCCESS
&& value_type
== (DWORD
) REG_DWORD
) {
228 windows_service_registry_write_string(const char * const key
,
229 const char * const value
)
235 value_len
= strlen(value
);
236 if (value_len
> 0x7fffffff) {
239 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE
,
240 WINDOWS_SERVICE_REGISTRY_PARAMETERS_KEY
,
241 (DWORD
) 0, NULL
, REG_OPTION_NON_VOLATILE
, KEY_WRITE
,
242 NULL
, &hk
, NULL
) != ERROR_SUCCESS
) {
245 if (RegSetValueEx(hk
, key
, NULL
, REG_SZ
, (const BYTE
*) value
,
246 (DWORD
) value_len
) != ERROR_SUCCESS
) {
255 windows_build_command_line_from_registry(int * const argc_p
,
256 char *** const argv_p
)
258 char dword_string
[sizeof "2147483648"];
263 if ((*argv_p
= cmdline_clone_options(*argc_p
, *argv_p
)) == NULL
) {
266 if (windows_service_registry_read_string
267 ("ResolversList", &string_value
) == 0) {
268 err
+= cmdline_add_option(argc_p
, argv_p
, "--resolvers-list");
269 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
272 if (windows_service_registry_read_string
273 ("ResolverName", &string_value
) == 0) {
274 err
+= cmdline_add_option(argc_p
, argv_p
, "--resolver-name");
275 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
278 if (windows_service_registry_read_string
279 ("LocalAddress", &string_value
) == 0) {
280 err
+= cmdline_add_option(argc_p
, argv_p
, "--local-address");
281 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
284 if (windows_service_registry_read_string
285 ("ProviderKey", &string_value
) == 0) {
286 err
+= cmdline_add_option(argc_p
, argv_p
, "--provider-key");
287 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
290 if (windows_service_registry_read_string
291 ("ProviderName", &string_value
) == 0) {
292 err
+= cmdline_add_option(argc_p
, argv_p
, "--provider-name");
293 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
296 if (windows_service_registry_read_string
297 ("ResolverAddress", &string_value
) == 0) {
298 err
+= cmdline_add_option(argc_p
, argv_p
, "--resolver-address");
299 err
+= cmdline_add_option(argc_p
, argv_p
, string_value
);
302 if (windows_service_registry_read_dword
303 ("EDNSPayloadSize", &dword_value
) == 0) {
304 snprintf(dword_string
, sizeof dword_string
, "%ld", (long) dword_value
);
305 err
+= cmdline_add_option(argc_p
, argv_p
, "--edns-payload-size");
306 err
+= cmdline_add_option(argc_p
, argv_p
, dword_string
);
308 if (windows_service_registry_read_dword
309 ("MaxActiveRequests", &dword_value
) == 0) {
310 snprintf(dword_string
, sizeof dword_string
, "%ld", (long) dword_value
);
311 err
+= cmdline_add_option(argc_p
, argv_p
, "--max-active-requests");
312 err
+= cmdline_add_option(argc_p
, argv_p
, dword_string
);
314 if (windows_service_registry_read_dword
315 ("TCPOnly", &dword_value
) == 0 && dword_value
> (DWORD
) 0) {
316 err
+= cmdline_add_option(argc_p
, argv_p
, "--tcp-only");
318 windows_service_registry_read_multi_sz
319 ("Plugins", & (WindowsServiceParseMultiSzCb
) {
320 .cb
= windows_service_parse_multi_sz_cb
,
332 service_main(DWORD argc_
, LPTSTR
*argv_
)
334 char **argv
= (char **) argv_
;
335 int argc
= (int) argc_
;
337 assert(argc_
< INT_MAX
);
338 if (windows_build_command_line_from_registry(&argc
, &argv
) != 0) {
339 logger_noformat(NULL
, LOG_ERR
,
340 "Unable to build a command line from the registry");
343 memset(&service_status
, 0, sizeof service_status
);
344 service_status
.dwServiceType
= SERVICE_WIN32
;
345 service_status
.dwCurrentState
= SERVICE_START_PENDING
;
346 service_status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
347 service_status_handle
=
348 RegisterServiceCtrlHandler(WINDOWS_SERVICE_NAME
, control_handler
);
349 if (service_status_handle
== 0) {
352 service_status
.dwCurrentState
= SERVICE_RUNNING
;
353 SetServiceStatus(service_status_handle
, &service_status
);
355 dnscrypt_proxy_main(argc
, argv
);
359 windows_main(int argc
, char *argv
[])
361 static SERVICE_TABLE_ENTRY service_table
[2];
364 if ((service_name
= strdup(WINDOWS_SERVICE_NAME
)) == NULL
) {
368 memcpy(service_table
, (SERVICE_TABLE_ENTRY
[2]) {
369 { .lpServiceName
= service_name
, .lpServiceProc
= service_main
},
370 { .lpServiceName
= NULL
, .lpServiceProc
= (void *) NULL
}
371 }, sizeof service_table
);
372 if (StartServiceCtrlDispatcher(service_table
) == 0) {
374 return dnscrypt_proxy_main(argc
, argv
);
376 app_is_running_as_a_service
= 1;
382 windows_service_uninstall(void)
384 SC_HANDLE scm_handle
;
385 SC_HANDLE service_handle
;
386 SERVICE_STATUS service_status
;
389 scm_handle
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
390 if (scm_handle
== NULL
) {
393 service_handle
= OpenService(scm_handle
, WINDOWS_SERVICE_NAME
,
394 DELETE
| SERVICE_STOP
);
395 if (service_handle
== NULL
) {
396 CloseServiceHandle(scm_handle
);
399 ControlService(service_handle
, SERVICE_CONTROL_STOP
, &service_status
);
400 if (DeleteService(service_handle
) == 0) {
403 CloseServiceHandle(service_handle
);
404 CloseServiceHandle(scm_handle
);
410 windows_registry_install(ProxyContext
* const proxy_context
)
412 if (proxy_context
->resolvers_list
!= NULL
) {
413 windows_service_registry_write_string("ResolversList",
414 proxy_context
->resolvers_list
);
416 if (proxy_context
->resolver_name
!= NULL
) {
417 windows_service_registry_write_string("ResolverName",
418 proxy_context
->resolver_name
);
420 if (proxy_context
->local_ip
!= NULL
) {
421 windows_service_registry_write_string("LocalAddress",
422 proxy_context
->local_ip
);
428 windows_service_install(ProxyContext
* const proxy_context
)
430 char self_path
[MAX_PATH
];
431 SC_HANDLE scm_handle
;
432 SC_HANDLE service_handle
;
434 if (windows_registry_install(proxy_context
) != 0) {
435 logger_noformat(proxy_context
, LOG_ERR
,
436 "Unable to set up registry keys");
439 if (GetModuleFileName(NULL
, self_path
, MAX_PATH
) <= (DWORD
) 0) {
442 scm_handle
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
443 if (scm_handle
== NULL
) {
446 service_handle
= CreateService
447 (scm_handle
, WINDOWS_SERVICE_NAME
,
448 WINDOWS_SERVICE_NAME
, SERVICE_ALL_ACCESS
,
449 SERVICE_WIN32_OWN_PROCESS
, SERVICE_AUTO_START
,
450 SERVICE_ERROR_NORMAL
, self_path
, NULL
, NULL
, NULL
, NULL
, NULL
);
451 if (service_handle
== NULL
) {
452 CloseServiceHandle(scm_handle
);
455 StartService(service_handle
, (DWORD
) 0, NULL
);
456 CloseServiceHandle(service_handle
);
457 CloseServiceHandle(scm_handle
);
463 main(int argc
, char *argv
[])
465 return windows_main(argc
, argv
);