dnscrypto-proxy: Update to release 1.3.0
[tomato.git] / release / src / router / dnscrypt / src / proxy / options.c
blob1dbc14fbcca7c943f1a249ac7b758078153908af
2 #include <config.h>
3 #include <sys/types.h>
4 #ifdef _WIN32
5 # include <winsock2.h>
6 #else
7 # include <sys/socket.h>
8 #endif
10 #include <assert.h>
11 #include <fcntl.h>
12 #include <getopt.h>
13 #include <limits.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
19 #include "dnscrypt_proxy.h"
20 #include "getpwnam.h"
21 #include "options.h"
22 #include "logger.h"
23 #include "pid_file.h"
24 #include "utils.h"
25 #include "windows_service.h"
26 #ifdef PLUGINS
27 # include "plugin_options.h"
28 #endif
30 static struct option getopt_long_options[] = {
31 { "local-address", 1, NULL, 'a' },
32 #ifndef _WIN32
33 { "daemonize", 0, NULL, 'd' },
34 #endif
35 { "edns-payload-size", 1, NULL, 'e' },
36 { "help", 0, NULL, 'h' },
37 { "provider-key", 1, NULL, 'k' },
38 #ifndef _WIN32
39 { "logfile", 1, NULL, 'l' },
40 #endif
41 { "loglevel", 1, NULL, 'm' },
42 { "max-active-requests", 1, NULL, 'n' },
43 #ifndef _WIN32
44 { "pidfile", 1, NULL, 'p' },
45 #endif
46 { "plugin", 1, NULL, 'X' },
47 { "resolver-address", 1, NULL, 'r' },
48 { "user", 1, NULL, 'u' },
49 { "provider-name", 1, NULL, 'N' },
50 { "tcp-only", 0, NULL, 'T' },
51 { "version", 0, NULL, 'V' },
52 #ifdef _WIN32
53 { "install", 0, NULL, WIN_OPTION_INSTALL },
54 { "reinstall", 0, NULL, WIN_OPTION_REINSTALL },
55 { "uninstall", 0, NULL, WIN_OPTION_UNINSTALL },
56 #endif
57 { NULL, 0, NULL, 0 }
59 #ifndef _WIN32
60 static const char *getopt_options = "a:de:hk:l:m:n:p:r:u:N:TVX";
61 #else
62 static const char *getopt_options = "a:e:hk:m:n:r:u:N:TVX";
63 #endif
65 #ifndef DEFAULT_CONNECTIONS_COUNT_MAX
66 # define DEFAULT_CONNECTIONS_COUNT_MAX 250U
67 #endif
69 #ifndef DEFAULT_PROVIDER_PUBLICKEY
70 # define DEFAULT_PROVIDER_PUBLICKEY \
71 "B735:1140:206F:225D:3E2B:D822:D7FD:691E:" \
72 "A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79"
73 #endif
74 #ifndef DEFAULT_PROVIDER_NAME
75 # define DEFAULT_PROVIDER_NAME "2.dnscrypt-cert.opendns.com."
76 #endif
77 #ifndef DEFAULT_RESOLVER_IP
78 # define DEFAULT_RESOLVER_IP "208.67.220.220:443"
79 #endif
81 static void
82 options_version(void)
84 puts(PACKAGE_STRING);
87 static void
88 options_usage(void)
90 const struct option *options = getopt_long_options;
92 options_version();
93 puts("\nOptions:\n");
94 do {
95 if (options->val < 256) {
96 printf(" -%c\t--%s%s\n", options->val, options->name,
97 options->has_arg ? "=..." : "");
98 } else {
99 printf(" \t--%s%s\n", options->name,
100 options->has_arg ? "=..." : "");
102 options++;
103 } while (options->name != NULL);
104 puts("\nPlease consult the dnscrypt-proxy(8) man page for details.\n");
107 static
108 void options_init_with_default(AppContext * const app_context,
109 ProxyContext * const proxy_context)
111 assert(proxy_context->event_loop == NULL);
112 proxy_context->app_context = app_context;
113 proxy_context->connections_count = 0U;
114 proxy_context->connections_count_max = DEFAULT_CONNECTIONS_COUNT_MAX;
115 proxy_context->edns_payload_size = (size_t) DNS_DEFAULT_EDNS_PAYLOAD_SIZE;
116 proxy_context->local_ip = "127.0.0.1:53";
117 proxy_context->log_fd = -1;
118 proxy_context->log_file = NULL;
119 proxy_context->pid_file = NULL;
120 proxy_context->provider_name = DEFAULT_PROVIDER_NAME;
121 proxy_context->provider_publickey_s = DEFAULT_PROVIDER_PUBLICKEY;
122 proxy_context->resolver_ip = DEFAULT_RESOLVER_IP;
123 #ifndef _WIN32
124 proxy_context->user_id = (uid_t) 0;
125 proxy_context->user_group = (uid_t) 0;
126 #endif
127 proxy_context->user_dir = NULL;
128 proxy_context->daemonize = 0;
129 proxy_context->tcp_only = 0;
132 static int
133 options_apply(ProxyContext * const proxy_context)
135 if (proxy_context->resolver_ip == NULL) {
136 options_usage();
137 exit(1);
139 if (proxy_context->provider_name == NULL ||
140 *proxy_context->provider_name == 0) {
141 logger_noformat(proxy_context, LOG_ERR, "Provider name required");
142 exit(1);
144 if (proxy_context->provider_publickey_s == NULL) {
145 logger_noformat(proxy_context, LOG_ERR, "Provider key required");
146 exit(1);
148 if (dnscrypt_fingerprint_to_key(proxy_context->provider_publickey_s,
149 proxy_context->provider_publickey) != 0) {
150 logger_noformat(proxy_context, LOG_ERR, "Invalid provider key");
151 exit(1);
153 if (proxy_context->daemonize) {
154 do_daemonize();
156 #ifndef _WIN32
157 if (proxy_context->pid_file != NULL &&
158 pid_file_create(proxy_context->pid_file,
159 proxy_context->user_id != (uid_t) 0) != 0) {
160 logger_error(proxy_context, "Unable to create pid file");
162 #endif
163 if (proxy_context->log_file != NULL &&
164 (proxy_context->log_fd = open(proxy_context->log_file,
165 O_WRONLY | O_APPEND | O_CREAT,
166 (mode_t) 0600)) == -1) {
167 logger_error(proxy_context, "Unable to open log file");
168 exit(1);
170 if (proxy_context->log_fd == -1 && proxy_context->daemonize) {
171 logger_open_syslog(proxy_context);
173 return 0;
177 options_parse(AppContext * const app_context,
178 ProxyContext * const proxy_context, int argc, char *argv[])
180 int opt_flag;
181 int option_index = 0;
183 options_init_with_default(app_context, proxy_context);
184 while ((opt_flag = getopt_long(argc, argv,
185 getopt_options, getopt_long_options,
186 &option_index)) != -1) {
187 switch (opt_flag) {
188 case 'a':
189 proxy_context->local_ip = optarg;
190 break;
191 case 'd':
192 proxy_context->daemonize = 1;
193 break;
194 case 'e': {
195 char *endptr;
196 const unsigned long edns_payload_size = strtoul(optarg, &endptr, 10);
198 if (*optarg == 0 || *endptr != 0 ||
199 edns_payload_size > DNS_MAX_PACKET_SIZE_UDP_RECV) {
200 logger(proxy_context, LOG_ERR,
201 "Invalid EDNS payload size: [%s]", optarg);
202 exit(1);
204 if (edns_payload_size <= DNS_MAX_PACKET_SIZE_UDP_SEND) {
205 proxy_context->edns_payload_size = (size_t) 0U;
206 } else {
207 proxy_context->edns_payload_size = (size_t) edns_payload_size;
209 break;
211 case 'h':
212 options_usage();
213 exit(0);
214 case 'k':
215 proxy_context->provider_publickey_s = optarg;
216 break;
217 case 'l':
218 proxy_context->log_file = optarg;
219 break;
220 case 'm': {
221 char *endptr;
222 const long max_log_level = strtol(optarg, &endptr, 10);
224 if (*optarg == 0 || *endptr != 0 || max_log_level < 0) {
225 logger(proxy_context, LOG_ERR,
226 "Invalid max log level: [%s]", optarg);
227 exit(1);
229 proxy_context->max_log_level = max_log_level;
230 break;
232 case 'n': {
233 char *endptr;
234 const unsigned long connections_count_max =
235 strtoul(optarg, &endptr, 10);
237 if (*optarg == 0 || *endptr != 0 ||
238 connections_count_max <= 0U ||
239 connections_count_max > UINT_MAX) {
240 logger(proxy_context, LOG_ERR,
241 "Invalid max number of active request: [%s]", optarg);
242 exit(1);
244 proxy_context->connections_count_max =
245 (unsigned int) connections_count_max;
246 break;
248 case 'p':
249 proxy_context->pid_file = optarg;
250 break;
251 case 'r':
252 proxy_context->resolver_ip = optarg;
253 break;
254 #ifdef HAVE_GETPWNAM
255 case 'u': {
256 const struct passwd * const pw = getpwnam(optarg);
257 if (pw == NULL) {
258 logger(proxy_context, LOG_ERR, "Unknown user: [%s]", optarg);
259 exit(1);
261 proxy_context->user_id = pw->pw_uid;
262 proxy_context->user_group = pw->pw_gid;
263 proxy_context->user_dir = strdup(pw->pw_dir);
264 break;
266 #endif
267 case 'N':
268 proxy_context->provider_name = optarg;
269 break;
270 case 'T':
271 proxy_context->tcp_only = 1;
272 break;
273 case 'V':
274 options_version();
275 exit(0);
276 case 'X':
277 #ifndef PLUGINS
278 logger_noformat(proxy_context, LOG_ERR,
279 "Support for plugins hasn't been compiled in");
280 exit(1);
281 #else
282 if (plugin_options_parse_str
283 (proxy_context->app_context->dcps_context, optarg) != 0) {
284 logger_noformat(proxy_context, LOG_ERR,
285 "Error while parsing plugin options");
286 exit(2);
288 #endif
289 break;
290 #ifdef _WIN32
291 case WIN_OPTION_INSTALL:
292 case WIN_OPTION_UNINSTALL:
293 if (windows_service_option(opt_flag, argc,
294 (const char **) argv) != 0) {
295 options_usage();
296 exit(1);
298 break;
299 #endif
300 default:
301 options_usage();
302 exit(1);
305 if (options_apply(proxy_context) != 0) {
306 return -1;
308 return 0;
311 void
312 options_free(ProxyContext * const proxy_context)
314 free(proxy_context->user_dir);
315 proxy_context->user_dir = NULL;