15 #include <event2/event.h>
16 #include <event2/util.h>
21 #include "dnscrypt_client.h"
22 #include "dnscrypt_proxy.h"
25 #include "sandboxes.h"
26 #include "stack_trace.h"
27 #include "tcp_request.h"
28 #include "udp_request.h"
30 # include "plugin_support.h"
33 #ifndef INET6_ADDRSTRLEN
34 # define INET6_ADDRSTRLEN 46U
37 static AppContext app_context
;
38 static volatile sig_atomic_t skip_dispatch
;
41 sockaddr_from_ip_and_port(struct sockaddr_storage
* const sockaddr
,
42 ev_socklen_t
* const sockaddr_len_p
,
43 const char * const ip
, const char * const port
,
44 const char * const error_msg
)
46 char sockaddr_port
[INET6_ADDRSTRLEN
+ sizeof "[]:65535"];
50 _Bool has_columns
= 0;
51 _Bool has_brackets
= *ip
== '[';
53 if ((pnt
= strchr(ip
, ':')) != NULL
) {
55 if (strchr(pnt
+ 1, ':') != NULL
) {
59 sockaddr_len_int
= (int) sizeof *sockaddr
;
60 if ((has_brackets
!= 0 || has_column
!= has_columns
) &&
61 evutil_parse_sockaddr_port(ip
, (struct sockaddr
*) sockaddr
,
62 &sockaddr_len_int
) == 0) {
63 *sockaddr_len_p
= (ev_socklen_t
) sockaddr_len_int
;
66 if (has_columns
!= 0 && has_brackets
== 0) {
67 evutil_snprintf(sockaddr_port
, sizeof sockaddr_port
, "[%s]:%s",
70 evutil_snprintf(sockaddr_port
, sizeof sockaddr_port
, "%s:%s",
73 sockaddr_len_int
= (int) sizeof *sockaddr
;
74 if (evutil_parse_sockaddr_port(sockaddr_port
, (struct sockaddr
*) sockaddr
,
75 &sockaddr_len_int
) != 0) {
76 logger(NULL
, LOG_ERR
, "%s: %s", error_msg
, sockaddr_port
);
77 *sockaddr_len_p
= (ev_socklen_t
) 0U;
81 *sockaddr_len_p
= (ev_socklen_t
) sockaddr_len_int
;
87 proxy_context_init(ProxyContext
* const proxy_context
, int argc
, char *argv
[])
89 memset(proxy_context
, 0, sizeof *proxy_context
);
90 proxy_context
->event_loop
= NULL
;
91 proxy_context
->log_file
= NULL
;
92 proxy_context
->max_log_level
= LOG_INFO
;
93 proxy_context
->tcp_accept_timer
= NULL
;
94 proxy_context
->tcp_conn_listener
= NULL
;
95 proxy_context
->udp_current_max_size
= DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND
;
96 proxy_context
->udp_max_size
= proxy_context
->udp_current_max_size
;
97 proxy_context
->udp_listener_event
= NULL
;
98 proxy_context
->udp_proxy_resolver_event
= NULL
;
99 proxy_context
->udp_proxy_resolver_handle
= -1;
100 proxy_context
->udp_listener_handle
= -1;
101 if (options_parse(&app_context
, proxy_context
, argc
, argv
) != 0) {
106 WSAStartup(MAKEWORD(2, 2), &wsa_data
);
108 if ((proxy_context
->event_loop
= event_base_new()) == NULL
) {
109 logger(NULL
, LOG_ERR
, "Unable to initialize the event loop");
112 if (sockaddr_from_ip_and_port(&proxy_context
->resolver_sockaddr
,
113 &proxy_context
->resolver_sockaddr_len
,
114 proxy_context
->resolver_ip
,
115 DNS_DEFAULT_RESOLVER_PORT
,
116 "Unsupported resolver address") != 0) {
119 if (sockaddr_from_ip_and_port(&proxy_context
->local_sockaddr
,
120 &proxy_context
->local_sockaddr_len
,
121 proxy_context
->local_ip
,
122 DNS_DEFAULT_LOCAL_PORT
,
123 "Unsupported local address") != 0) {
130 proxy_context_free(ProxyContext
* const proxy_context
)
132 if (proxy_context
== NULL
) {
135 options_free(proxy_context
);
136 logger_close(proxy_context
);
142 setlocale(LC_CTYPE
, "C");
143 setlocale(LC_COLLATE
, "C");
151 static char default_tz_for_putenv
[] = "TZ=UTC+00:00";
158 if ((tm
= localtime(&now
)) != NULL
&&
159 strftime(stbuf
, sizeof stbuf
, "%z", tm
) == (size_t) 5U) {
160 evutil_snprintf(default_tz_for_putenv
, sizeof default_tz_for_putenv
,
161 "TZ=UTC%c%c%c:%c%c", (*stbuf
== '-' ? '+' : '-'),
162 stbuf
[1], stbuf
[2], stbuf
[3], stbuf
[4]);
164 putenv(default_tz_for_putenv
);
165 (void) localtime(&now
);
172 revoke_privileges(ProxyContext
* const proxy_context
)
174 (void) proxy_context
;
178 (void) strerror(ENOENT
);
182 if (proxy_context
->user_dir
!= NULL
) {
183 if (chdir(proxy_context
->user_dir
) != 0 ||
184 chroot(proxy_context
->user_dir
) != 0 || chdir("/") != 0) {
185 logger(proxy_context
, LOG_ERR
, "Unable to chroot to [%s]",
186 proxy_context
->user_dir
);
190 if (sandboxes_app() != 0) {
191 logger_noformat(proxy_context
, LOG_ERR
,
192 "Unable to sandbox the main process");
195 if (proxy_context
->user_id
!= (uid_t
) 0) {
196 if (setgid(proxy_context
->user_group
) != 0 ||
197 setegid(proxy_context
->user_group
) != 0 ||
198 setuid(proxy_context
->user_id
) != 0 ||
199 seteuid(proxy_context
->user_id
) != 0) {
200 logger(proxy_context
, LOG_ERR
, "Unable to switch to user id [%lu]",
201 (unsigned long) proxy_context
->user_id
);
210 dnscrypt_proxy_start_listeners(ProxyContext
* const proxy_context
)
212 char local_addr_s
[INET6_ADDRSTRLEN
+ sizeof "[]:65535"];
213 char resolver_addr_s
[INET6_ADDRSTRLEN
+ sizeof "[]:65535"];
215 if (proxy_context
->listeners_started
!= 0) {
218 if (udp_listener_start(proxy_context
) != 0 ||
219 tcp_listener_start(proxy_context
) != 0) {
222 evutil_format_sockaddr_port((const struct sockaddr
*)
223 &proxy_context
->local_sockaddr
,
224 local_addr_s
, sizeof local_addr_s
);
225 evutil_format_sockaddr_port((const struct sockaddr
*)
226 &proxy_context
->resolver_sockaddr
,
227 resolver_addr_s
, sizeof resolver_addr_s
);
228 logger(proxy_context
, LOG_NOTICE
, "Proxying from %s to %s",
229 local_addr_s
, resolver_addr_s
);
231 proxy_context
->listeners_started
= 1;
237 dnscrypt_proxy_loop_break(void)
239 if (app_context
.proxy_context
!= NULL
&&
240 app_context
.proxy_context
->event_loop
!= NULL
) {
241 event_base_loopbreak(app_context
.proxy_context
->event_loop
);
249 dnscrypt_proxy_main(int argc
, char *argv
[])
251 ProxyContext proxy_context
;
253 setvbuf(stdout
, NULL
, _IOLBF
, BUFSIZ
);
254 stack_trace_on_crash();
256 if ((app_context
.dcps_context
= plugin_support_context_new()) == NULL
) {
257 logger_noformat(NULL
, LOG_ERR
, "Unable to setup plugin support");
261 if (proxy_context_init(&proxy_context
, argc
, argv
) != 0) {
262 logger_noformat(NULL
, LOG_ERR
, "Unable to start the proxy");
265 logger_noformat(&proxy_context
, LOG_NOTICE
, "Starting " PACKAGE_STRING
);
266 #ifdef USE_ONLY_PORTABLE_IMPLEMENTATIONS
269 logger_noformat(&proxy_context
, LOG_INFO
,
270 "Initializing libsodium for optimal performance");
271 if (sodium_init() != 0) {
275 #ifdef HAVE_SODIUM_MLOCK
276 sodium_mlock(&proxy_context
, sizeof proxy_context
);
278 randombytes_set_implementation(&randombytes_salsa20_implementation
);
280 if (plugin_support_context_load(app_context
.dcps_context
) != 0) {
281 logger_noformat(NULL
, LOG_ERR
, "Unable to load plugins");
285 app_context
.proxy_context
= &proxy_context
;
286 logger_noformat(&proxy_context
, LOG_INFO
, "Generating a new key pair");
287 dnscrypt_client_init_with_new_key_pair(&proxy_context
.dnscrypt_client
);
288 logger_noformat(&proxy_context
, LOG_INFO
, "Done");
290 if (cert_updater_init(&proxy_context
) != 0) {
293 if (proxy_context
.test_only
== 0 &&
294 (udp_listener_bind(&proxy_context
) != 0 ||
295 tcp_listener_bind(&proxy_context
) != 0)) {
299 signal(SIGPIPE
, SIG_IGN
);
302 revoke_privileges(&proxy_context
);
303 if (cert_updater_start(&proxy_context
) != 0) {
306 if (skip_dispatch
== 0) {
307 event_base_dispatch(proxy_context
.event_loop
);
309 logger_noformat(&proxy_context
, LOG_NOTICE
, "Stopping proxy");
310 cert_updater_free(&proxy_context
);
311 udp_listener_stop(&proxy_context
);
312 tcp_listener_stop(&proxy_context
);
313 event_base_free(proxy_context
.event_loop
);
315 plugin_support_context_free(app_context
.dcps_context
);
317 proxy_context_free(&proxy_context
);
318 #ifdef HAVE_SODIUM_MLOCK
319 sodium_munlock(&proxy_context
, sizeof proxy_context
);
321 app_context
.proxy_context
= NULL
;