Changes to update Tomato RAF.
[tomato.git] / release / src / router / dnscrypt / src / proxy / app.c
blob74dc17202cc35215a5f6664740e004d5e04262ae
2 #include <config.h>
3 #include <sys/types.h>
5 #include <errno.h>
6 #include <signal.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <unistd.h>
13 #include <event2/event.h>
14 #include <event2/util.h>
16 #include "app.h"
17 #include "dnscrypt_client.h"
18 #include "dnscrypt_proxy.h"
19 #include "salsa20_random.h"
20 #include "logger.h"
21 #include "options.h"
22 #include "sandboxes.h"
23 #include "stack_trace.h"
24 #include "tcp_request.h"
25 #include "udp_request.h"
27 #ifndef INET6_ADDRSTRLEN
28 # define INET6_ADDRSTRLEN 46U
29 #endif
31 static AppContext app_context;
33 static int
34 sockaddr_from_ip_and_port(struct sockaddr_storage * const sockaddr,
35 ev_socklen_t * const sockaddr_len_p,
36 const char * const ip, const char * const port,
37 const char * const error_msg)
39 char sockaddr_port[INET6_ADDRSTRLEN + sizeof "[]:65535"];
40 int sockaddr_len_int;
41 char *pnt;
42 _Bool has_column = 0;
43 _Bool has_columns = 0;
44 _Bool has_brackets = *ip == '[';
46 if ((pnt = strchr(ip, ':')) != NULL) {
47 has_column = 1;
48 if (strchr(pnt + 1, ':') != NULL) {
49 has_columns = 1;
52 sockaddr_len_int = (int) sizeof *sockaddr;
53 if ((has_brackets != 0 || has_column != has_columns) &&
54 evutil_parse_sockaddr_port(ip, (struct sockaddr *) sockaddr,
55 &sockaddr_len_int) == 0) {
56 *sockaddr_len_p = (ev_socklen_t) sockaddr_len_int;
57 return 0;
59 if (has_columns != 0 && has_brackets == 0) {
60 evutil_snprintf(sockaddr_port, sizeof sockaddr_port, "[%s]:%s",
61 ip, port);
62 } else {
63 evutil_snprintf(sockaddr_port, sizeof sockaddr_port, "%s:%s",
64 ip, port);
66 sockaddr_len_int = (int) sizeof *sockaddr;
67 if (evutil_parse_sockaddr_port(sockaddr_port, (struct sockaddr *) sockaddr,
68 &sockaddr_len_int) != 0) {
69 logger(NULL, LOG_ERR, "%s: %s", error_msg, sockaddr_port);
70 *sockaddr_len_p = (ev_socklen_t) 0U;
72 return -1;
74 *sockaddr_len_p = (ev_socklen_t) sockaddr_len_int;
76 return 0;
79 static int
80 proxy_context_init(ProxyContext * const proxy_context, int argc, char *argv[])
82 memset(proxy_context, 0, sizeof *proxy_context);
83 proxy_context->event_loop = NULL;
84 proxy_context->tcp_accept_timer = NULL;
85 proxy_context->tcp_conn_listener = NULL;
86 proxy_context->udp_listener_event = NULL;
87 proxy_context->udp_proxy_resolver_event = NULL;
88 proxy_context->udp_proxy_resolver_handle = -1;
89 proxy_context->udp_listener_handle = -1;
90 if (options_parse(&app_context, proxy_context, argc, argv) != 0) {
91 return -1;
93 #ifdef _WIN32
94 WSADATA wsa_data;
95 WSAStartup(MAKEWORD(2, 2), &wsa_data);
96 #endif
97 if ((proxy_context->event_loop = event_base_new()) == NULL) {
98 logger(NULL, LOG_ERR, "Unable to initialize the event loop");
99 return -1;
101 if (sockaddr_from_ip_and_port(&proxy_context->resolver_sockaddr,
102 &proxy_context->resolver_sockaddr_len,
103 proxy_context->resolver_ip,
104 proxy_context->resolver_port,
105 "Unsupported resolver address") != 0) {
106 return -1;
108 if (sockaddr_from_ip_and_port(&proxy_context->local_sockaddr,
109 &proxy_context->local_sockaddr_len,
110 proxy_context->local_ip,
111 proxy_context->local_port,
112 "Unsupported local address") != 0) {
113 return -1;
115 return 0;
118 static void
119 proxy_context_free(ProxyContext * const proxy_context)
121 if (proxy_context == NULL) {
122 return;
124 options_free(proxy_context);
125 logger_close(proxy_context);
128 static
129 int init_tz(void)
131 static char default_tz_for_putenv[] = "TZ=UTC+00:00";
132 char stbuf[10U];
133 struct tm *tm;
134 time_t now;
136 tzset();
137 time(&now);
138 if ((tm = localtime(&now)) != NULL &&
139 strftime(stbuf, sizeof stbuf, "%z", tm) == (size_t) 5U) {
140 evutil_snprintf(default_tz_for_putenv, sizeof default_tz_for_putenv,
141 "TZ=UTC%c%c%c:%c%c", (*stbuf == '-' ? '+' : '-'),
142 stbuf[1], stbuf[2], stbuf[3], stbuf[4]);
144 putenv(default_tz_for_putenv);
145 (void) localtime(&now);
146 (void) gmtime(&now);
148 return 0;
151 static void
152 revoke_privileges(ProxyContext * const proxy_context)
154 (void) proxy_context;
155 #ifndef DEBUG
156 salsa20_random_stir();
157 init_tz();
158 (void) strerror(ENOENT);
159 # ifndef _WIN32
160 if (proxy_context->user_dir != NULL) {
161 if (chdir(proxy_context->user_dir) != 0 ||
162 chroot(proxy_context->user_dir) != 0 || chdir("/") != 0) {
163 logger(proxy_context, LOG_ERR, "Unable to chroot to [%s]",
164 proxy_context->user_dir);
165 exit(1);
168 if (sandboxes_app() != 0) {
169 logger_noformat(proxy_context, LOG_ERR,
170 "Unable to sandbox the main process");
171 exit(1);
173 if (proxy_context->user_id != (uid_t) 0) {
174 if (setgid(proxy_context->user_group) != 0 ||
175 setegid(proxy_context->user_group) != 0 ||
176 setuid(proxy_context->user_id) != 0 ||
177 seteuid(proxy_context->user_id) != 0) {
178 logger(proxy_context, LOG_ERR, "Unable to switch to user id [%lu]",
179 (unsigned long) proxy_context->user_id);
180 exit(1);
183 # endif
184 #endif
188 dnscrypt_proxy_start_listeners(ProxyContext * const proxy_context)
190 char local_addr_s[INET6_ADDRSTRLEN + sizeof "[]:65535"];
191 char resolver_addr_s[INET6_ADDRSTRLEN + sizeof "[]:65535"];
193 if (proxy_context->listeners_started != 0) {
194 return 0;
196 if (udp_listener_start(proxy_context) != 0 ||
197 tcp_listener_start(proxy_context) != 0) {
198 exit(1);
200 evutil_format_sockaddr_port((const struct sockaddr *)
201 &proxy_context->local_sockaddr,
202 local_addr_s, sizeof local_addr_s);
203 evutil_format_sockaddr_port((const struct sockaddr *)
204 &proxy_context->resolver_sockaddr,
205 resolver_addr_s, sizeof resolver_addr_s);
206 logger(proxy_context, LOG_INFO, "Proxying from %s to %s",
207 local_addr_s, resolver_addr_s);
209 proxy_context->listeners_started = 1;
211 return 0;
215 main(int argc, char *argv[])
217 ProxyContext proxy_context;
219 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
220 stack_trace_on_crash();
221 if (proxy_context_init(&proxy_context, argc, argv) != 0) {
222 logger_noformat(NULL, LOG_ERR, "Unable to start the proxy");
223 exit(1);
225 app_context.proxy_context = &proxy_context;
226 logger_noformat(&proxy_context, LOG_INFO, "Generating a new key pair");
227 dnscrypt_client_init_with_new_key_pair(&proxy_context.dnscrypt_client);
228 logger_noformat(&proxy_context, LOG_INFO, "Done");
230 if (cert_updater_init(&proxy_context) != 0 ||
231 udp_listener_bind(&proxy_context) != 0 ||
232 tcp_listener_bind(&proxy_context) != 0) {
233 exit(1);
235 #ifdef SIGPIPE
236 signal(SIGPIPE, SIG_IGN);
237 #endif
239 revoke_privileges(&proxy_context);
240 if (cert_updater_start(&proxy_context) != 0) {
241 exit(1);
243 event_base_dispatch(proxy_context.event_loop);
245 logger_noformat(&proxy_context, LOG_INFO, "Stopping proxy");
246 cert_updater_free(&proxy_context);
247 udp_listener_stop(&proxy_context);
248 tcp_listener_stop(&proxy_context);
249 event_base_free(proxy_context.event_loop);
250 proxy_context_free(&proxy_context);
251 app_context.proxy_context = NULL;
252 salsa20_random_close();
254 return 0;