15 #include <event2/event.h>
16 #include <event2/util.h>
19 #include "dnscrypt_client.h"
20 #include "dnscrypt_proxy.h"
23 #include "sandboxes.h"
25 #include "stack_trace.h"
26 #include "tcp_request.h"
27 #include "udp_request.h"
29 # include "plugin_support.h"
32 #ifndef INET6_ADDRSTRLEN
33 # define INET6_ADDRSTRLEN 46U
36 static AppContext app_context
;
37 static volatile sig_atomic_t skip_dispatch
;
40 sockaddr_from_ip_and_port(struct sockaddr_storage
* const sockaddr
,
41 ev_socklen_t
* const sockaddr_len_p
,
42 const char * const ip
, const char * const port
,
43 const char * const error_msg
)
45 char sockaddr_port
[INET6_ADDRSTRLEN
+ sizeof "[]:65535"];
49 _Bool has_columns
= 0;
50 _Bool has_brackets
= *ip
== '[';
52 if ((pnt
= strchr(ip
, ':')) != NULL
) {
54 if (strchr(pnt
+ 1, ':') != NULL
) {
58 sockaddr_len_int
= (int) sizeof *sockaddr
;
59 if ((has_brackets
!= 0 || has_column
!= has_columns
) &&
60 evutil_parse_sockaddr_port(ip
, (struct sockaddr
*) sockaddr
,
61 &sockaddr_len_int
) == 0) {
62 *sockaddr_len_p
= (ev_socklen_t
) sockaddr_len_int
;
65 if (has_columns
!= 0 && has_brackets
== 0) {
66 evutil_snprintf(sockaddr_port
, sizeof sockaddr_port
, "[%s]:%s",
69 evutil_snprintf(sockaddr_port
, sizeof sockaddr_port
, "%s:%s",
72 sockaddr_len_int
= (int) sizeof *sockaddr
;
73 if (evutil_parse_sockaddr_port(sockaddr_port
, (struct sockaddr
*) sockaddr
,
74 &sockaddr_len_int
) != 0) {
75 logger(NULL
, LOG_ERR
, "%s: %s", error_msg
, sockaddr_port
);
76 *sockaddr_len_p
= (ev_socklen_t
) 0U;
80 *sockaddr_len_p
= (ev_socklen_t
) sockaddr_len_int
;
86 proxy_context_init(ProxyContext
* const proxy_context
, int argc
, char *argv
[])
88 memset(proxy_context
, 0, sizeof *proxy_context
);
89 proxy_context
->event_loop
= NULL
;
90 proxy_context
->log_file
= NULL
;
91 proxy_context
->max_log_level
= LOG_INFO
;
92 proxy_context
->tcp_accept_timer
= NULL
;
93 proxy_context
->tcp_conn_listener
= NULL
;
94 proxy_context
->udp_listener_event
= NULL
;
95 proxy_context
->udp_proxy_resolver_event
= NULL
;
96 proxy_context
->udp_proxy_resolver_handle
= -1;
97 proxy_context
->udp_listener_handle
= -1;
98 if (options_parse(&app_context
, proxy_context
, argc
, argv
) != 0) {
103 WSAStartup(MAKEWORD(2, 2), &wsa_data
);
105 if ((proxy_context
->event_loop
= event_base_new()) == NULL
) {
106 logger(NULL
, LOG_ERR
, "Unable to initialize the event loop");
109 if (sockaddr_from_ip_and_port(&proxy_context
->resolver_sockaddr
,
110 &proxy_context
->resolver_sockaddr_len
,
111 proxy_context
->resolver_ip
,
112 DNS_DEFAULT_RESOLVER_PORT
,
113 "Unsupported resolver address") != 0) {
116 if (sockaddr_from_ip_and_port(&proxy_context
->local_sockaddr
,
117 &proxy_context
->local_sockaddr_len
,
118 proxy_context
->local_ip
,
119 DNS_DEFAULT_LOCAL_PORT
,
120 "Unsupported local address") != 0) {
127 proxy_context_free(ProxyContext
* const proxy_context
)
129 if (proxy_context
== NULL
) {
132 options_free(proxy_context
);
133 logger_close(proxy_context
);
139 setlocale(LC_CTYPE
, "C");
140 setlocale(LC_COLLATE
, "C");
148 static char default_tz_for_putenv
[] = "TZ=UTC+00:00";
155 if ((tm
= localtime(&now
)) != NULL
&&
156 strftime(stbuf
, sizeof stbuf
, "%z", tm
) == (size_t) 5U) {
157 evutil_snprintf(default_tz_for_putenv
, sizeof default_tz_for_putenv
,
158 "TZ=UTC%c%c%c:%c%c", (*stbuf
== '-' ? '+' : '-'),
159 stbuf
[1], stbuf
[2], stbuf
[3], stbuf
[4]);
161 putenv(default_tz_for_putenv
);
162 (void) localtime(&now
);
169 revoke_privileges(ProxyContext
* const proxy_context
)
171 (void) proxy_context
;
175 (void) strerror(ENOENT
);
179 if (proxy_context
->user_dir
!= NULL
) {
180 if (chdir(proxy_context
->user_dir
) != 0 ||
181 chroot(proxy_context
->user_dir
) != 0 || chdir("/") != 0) {
182 logger(proxy_context
, LOG_ERR
, "Unable to chroot to [%s]",
183 proxy_context
->user_dir
);
187 if (sandboxes_app() != 0) {
188 logger_noformat(proxy_context
, LOG_ERR
,
189 "Unable to sandbox the main process");
192 if (proxy_context
->user_id
!= (uid_t
) 0) {
193 if (setgid(proxy_context
->user_group
) != 0 ||
194 setegid(proxy_context
->user_group
) != 0 ||
195 setuid(proxy_context
->user_id
) != 0 ||
196 seteuid(proxy_context
->user_id
) != 0) {
197 logger(proxy_context
, LOG_ERR
, "Unable to switch to user id [%lu]",
198 (unsigned long) proxy_context
->user_id
);
207 dnscrypt_proxy_start_listeners(ProxyContext
* const proxy_context
)
209 char local_addr_s
[INET6_ADDRSTRLEN
+ sizeof "[]:65535"];
210 char resolver_addr_s
[INET6_ADDRSTRLEN
+ sizeof "[]:65535"];
212 if (proxy_context
->listeners_started
!= 0) {
215 if (udp_listener_start(proxy_context
) != 0 ||
216 tcp_listener_start(proxy_context
) != 0) {
219 evutil_format_sockaddr_port((const struct sockaddr
*)
220 &proxy_context
->local_sockaddr
,
221 local_addr_s
, sizeof local_addr_s
);
222 evutil_format_sockaddr_port((const struct sockaddr
*)
223 &proxy_context
->resolver_sockaddr
,
224 resolver_addr_s
, sizeof resolver_addr_s
);
225 logger(proxy_context
, LOG_INFO
, "Proxying from %s to %s",
226 local_addr_s
, resolver_addr_s
);
228 proxy_context
->listeners_started
= 1;
234 dnscrypt_proxy_loop_break(void)
236 if (app_context
.proxy_context
!= NULL
&&
237 app_context
.proxy_context
->event_loop
!= NULL
) {
238 event_base_loopbreak(app_context
.proxy_context
->event_loop
);
246 dnscrypt_proxy_main(int argc
, char *argv
[])
248 ProxyContext proxy_context
;
250 setvbuf(stdout
, NULL
, _IOLBF
, BUFSIZ
);
251 stack_trace_on_crash();
253 if ((app_context
.dcps_context
= plugin_support_context_new()) == NULL
) {
254 logger_noformat(NULL
, LOG_ERR
, "Unable to setup plugin support");
258 if (proxy_context_init(&proxy_context
, argc
, argv
) != 0) {
259 logger_noformat(NULL
, LOG_ERR
, "Unable to start the proxy");
262 logger_noformat(&proxy_context
, LOG_INFO
,
263 "Initializing libsodium for optimal performance");
264 if (sodium_init() != 0) {
267 randombytes_set_implementation(&randombytes_salsa20_implementation
);
269 if (plugin_support_context_load(app_context
.dcps_context
) != 0) {
270 logger_noformat(NULL
, LOG_ERR
, "Unable to load plugins");
274 app_context
.proxy_context
= &proxy_context
;
275 logger_noformat(&proxy_context
, LOG_INFO
, "Generating a new key pair");
276 dnscrypt_client_init_with_new_key_pair(&proxy_context
.dnscrypt_client
);
277 logger_noformat(&proxy_context
, LOG_INFO
, "Done");
279 if (cert_updater_init(&proxy_context
) != 0 ||
280 udp_listener_bind(&proxy_context
) != 0 ||
281 tcp_listener_bind(&proxy_context
) != 0) {
285 signal(SIGPIPE
, SIG_IGN
);
288 revoke_privileges(&proxy_context
);
289 if (cert_updater_start(&proxy_context
) != 0) {
292 if (skip_dispatch
== 0) {
293 event_base_dispatch(proxy_context
.event_loop
);
295 logger_noformat(&proxy_context
, LOG_INFO
, "Stopping proxy");
296 cert_updater_free(&proxy_context
);
297 udp_listener_stop(&proxy_context
);
298 tcp_listener_stop(&proxy_context
);
299 event_base_free(proxy_context
.event_loop
);
301 plugin_support_context_free(app_context
.dcps_context
);
303 proxy_context_free(&proxy_context
);
304 app_context
.proxy_context
= NULL
;