dnscrypt-proxy update: 1.4.1
[tomato.git] / release / src / router / dnscrypt / src / proxy / app.c
blob69cf81ea4581b332d90fb26f35fd3297c568d631
2 #include <config.h>
3 #include <sys/types.h>
5 #include <assert.h>
6 #include <errno.h>
7 #include <locale.h>
8 #include <signal.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include <unistd.h>
15 #include <event2/event.h>
16 #include <event2/util.h>
18 #include <sodium.h>
20 #include "app.h"
21 #include "dnscrypt_client.h"
22 #include "dnscrypt_proxy.h"
23 #include "logger.h"
24 #include "options.h"
25 #include "sandboxes.h"
26 #include "stack_trace.h"
27 #include "tcp_request.h"
28 #include "udp_request.h"
29 #ifdef PLUGINS
30 # include "plugin_support.h"
31 #endif
33 #ifndef INET6_ADDRSTRLEN
34 # define INET6_ADDRSTRLEN 46U
35 #endif
37 static AppContext app_context;
38 static volatile sig_atomic_t skip_dispatch;
40 static int
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"];
47 int sockaddr_len_int;
48 char *pnt;
49 _Bool has_column = 0;
50 _Bool has_columns = 0;
51 _Bool has_brackets = *ip == '[';
53 if ((pnt = strchr(ip, ':')) != NULL) {
54 has_column = 1;
55 if (strchr(pnt + 1, ':') != NULL) {
56 has_columns = 1;
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;
64 return 0;
66 if (has_columns != 0 && has_brackets == 0) {
67 evutil_snprintf(sockaddr_port, sizeof sockaddr_port, "[%s]:%s",
68 ip, port);
69 } else {
70 evutil_snprintf(sockaddr_port, sizeof sockaddr_port, "%s:%s",
71 ip, port);
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;
79 return -1;
81 *sockaddr_len_p = (ev_socklen_t) sockaddr_len_int;
83 return 0;
86 static 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) {
102 return -1;
104 #ifdef _WIN32
105 WSADATA wsa_data;
106 WSAStartup(MAKEWORD(2, 2), &wsa_data);
107 #endif
108 if ((proxy_context->event_loop = event_base_new()) == NULL) {
109 logger(NULL, LOG_ERR, "Unable to initialize the event loop");
110 return -1;
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) {
117 return -1;
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) {
124 return -1;
126 return 0;
129 static void
130 proxy_context_free(ProxyContext * const proxy_context)
132 if (proxy_context == NULL) {
133 return;
135 options_free(proxy_context);
136 logger_close(proxy_context);
139 static int
140 init_locale(void)
142 setlocale(LC_CTYPE, "C");
143 setlocale(LC_COLLATE, "C");
145 return 0;
148 static int
149 init_tz(void)
151 static char default_tz_for_putenv[] = "TZ=UTC+00:00";
152 char stbuf[10U];
153 struct tm *tm;
154 time_t now;
156 tzset();
157 time(&now);
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);
166 (void) gmtime(&now);
168 return 0;
171 static void
172 revoke_privileges(ProxyContext * const proxy_context)
174 (void) proxy_context;
176 init_locale();
177 init_tz();
178 (void) strerror(ENOENT);
179 #ifndef DEBUG
180 randombytes_stir();
181 # ifndef _WIN32
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);
187 exit(1);
190 if (sandboxes_app() != 0) {
191 logger_noformat(proxy_context, LOG_ERR,
192 "Unable to sandbox the main process");
193 exit(1);
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);
202 exit(1);
205 # endif
206 #endif
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) {
216 return 0;
218 if (udp_listener_start(proxy_context) != 0 ||
219 tcp_listener_start(proxy_context) != 0) {
220 exit(1);
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;
233 return 0;
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);
242 } else {
243 skip_dispatch = 1;
245 return 0;
249 dnscrypt_proxy_main(int argc, char *argv[])
251 ProxyContext proxy_context;
253 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
254 stack_trace_on_crash();
255 #ifdef PLUGINS
256 if ((app_context.dcps_context = plugin_support_context_new()) == NULL) {
257 logger_noformat(NULL, LOG_ERR, "Unable to setup plugin support");
258 exit(2);
260 #endif
261 if (proxy_context_init(&proxy_context, argc, argv) != 0) {
262 logger_noformat(NULL, LOG_ERR, "Unable to start the proxy");
263 exit(1);
265 logger_noformat(&proxy_context, LOG_NOTICE, "Starting " PACKAGE_STRING);
266 #ifdef USE_ONLY_PORTABLE_IMPLEMENTATIONS
267 randombytes_stir();
268 #else
269 logger_noformat(&proxy_context, LOG_INFO,
270 "Initializing libsodium for optimal performance");
271 if (sodium_init() != 0) {
272 exit(1);
274 #endif
275 #ifdef HAVE_SODIUM_MLOCK
276 sodium_mlock(&proxy_context, sizeof proxy_context);
277 #endif
278 randombytes_set_implementation(&randombytes_salsa20_implementation);
279 #ifdef PLUGINS
280 if (plugin_support_context_load(app_context.dcps_context) != 0) {
281 logger_noformat(NULL, LOG_ERR, "Unable to load plugins");
282 exit(2);
284 #endif
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) {
291 exit(1);
293 if (proxy_context.test_only == 0 &&
294 (udp_listener_bind(&proxy_context) != 0 ||
295 tcp_listener_bind(&proxy_context) != 0)) {
296 exit(1);
298 #ifdef SIGPIPE
299 signal(SIGPIPE, SIG_IGN);
300 #endif
302 revoke_privileges(&proxy_context);
303 if (cert_updater_start(&proxy_context) != 0) {
304 exit(1);
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);
314 #ifdef PLUGINS
315 plugin_support_context_free(app_context.dcps_context);
316 #endif
317 proxy_context_free(&proxy_context);
318 #ifdef HAVE_SODIUM_MLOCK
319 sodium_munlock(&proxy_context, sizeof proxy_context);
320 #endif
321 app_context.proxy_context = NULL;
322 randombytes_close();
324 return 0;