Changes to update Tomato RAF.
[tomato.git] / release / src / router / dnscrypt / src / proxy / options.c
blob7ef07b24c5fe7f95962189c300ac9003dacddebc
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"
26 static struct option getopt_long_options[] = {
27 { "local-address", 1, NULL, 'a' },
28 #ifndef _WIN32
29 { "daemonize", 0, NULL, 'd' },
30 #endif
31 { "edns-payload-size", 1, NULL, 'e' },
32 { "help", 0, NULL, 'h' },
33 { "provider-key", 1, NULL, 'k' },
34 #ifndef _WIN32
35 { "logfile", 1, NULL, 'l' },
36 #endif
37 { "max-active-requests", 1, NULL, 'n' },
38 #ifndef _WIN32
39 { "pidfile", 1, NULL, 'p' },
40 #endif
41 { "resolver-address", 1, NULL, 'r' },
42 { "resolver-port", 1, NULL, 't' },
43 { "user", 1, NULL, 'u' },
44 { "provider-name", 1, NULL, 'N' },
45 { "local-port", 1, NULL, 'P' },
46 { "tcp-only", 0, NULL, 'T' },
47 { "version", 0, NULL, 'V' },
48 { NULL, 0, NULL, 0 }
50 #ifndef _WIN32
51 static const char *getopt_options = "a:de:hk:l:n:p:r:t:u:N:P:TV";
52 #else
53 static const char *getopt_options = "a:e:hk:n:r:t:u:N:P:TV";
54 #endif
56 #ifndef DEFAULT_CONNECTIONS_COUNT_MAX
57 # define DEFAULT_CONNECTIONS_COUNT_MAX 250U
58 #endif
60 #ifndef DEFAULT_PROVIDER_PUBLICKEY
61 # define DEFAULT_PROVIDER_PUBLICKEY \
62 "B735:1140:206F:225D:3E2B:D822:D7FD:691E:" \
63 "A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79"
64 #endif
65 #ifndef DEFAULT_PROVIDER_NAME
66 # define DEFAULT_PROVIDER_NAME "2.dnscrypt-cert.opendns.com."
67 #endif
68 #ifndef DEFAULT_RESOLVER_IP
69 # define DEFAULT_RESOLVER_IP "208.67.220.220"
70 #endif
72 static void
73 options_version(void)
75 puts(PACKAGE_STRING "\n"
76 "Copyright (C) 2011-2012 OpenDNS, Inc.");
79 static void
80 options_usage(void)
82 const struct option *options = getopt_long_options;
84 options_version();
85 puts("\nOptions:\n");
86 do {
87 printf(" -%c\t--%s%s\n", options->val, options->name,
88 options->has_arg ? "=..." : "");
89 options++;
90 } while (options->name != NULL);
91 puts("\nPlease consult the dnscrypt-proxy(8) man page for details.\n");
94 static
95 void options_init_with_default(AppContext * const app_context,
96 ProxyContext * const proxy_context)
98 assert(proxy_context->event_loop == NULL);
99 proxy_context->app_context = app_context;
100 proxy_context->connections_count = 0U;
101 proxy_context->connections_count_max = DEFAULT_CONNECTIONS_COUNT_MAX;
102 proxy_context->edns_payload_size = (size_t) DNS_DEFAULT_EDNS_PAYLOAD_SIZE;
103 proxy_context->local_ip = "127.0.0.1";
104 proxy_context->local_port = DNS_DEFAULT_LOCAL_PORT;
105 proxy_context->log_fd = -1;
106 proxy_context->log_file = NULL;
107 proxy_context->pid_file = NULL;
108 proxy_context->provider_name = DEFAULT_PROVIDER_NAME;
109 proxy_context->provider_publickey_s = DEFAULT_PROVIDER_PUBLICKEY;
110 proxy_context->resolver_ip = DEFAULT_RESOLVER_IP;
111 proxy_context->resolver_port = DNS_DEFAULT_RESOLVER_PORT;
112 #ifndef _WIN32
113 proxy_context->user_id = (uid_t) 0;
114 proxy_context->user_group = (uid_t) 0;
115 #endif
116 proxy_context->user_dir = NULL;
117 proxy_context->daemonize = 0;
118 proxy_context->tcp_only = 0;
121 static int
122 options_apply(ProxyContext * const proxy_context)
124 if (proxy_context->resolver_ip == NULL) {
125 options_usage();
126 exit(1);
128 if (proxy_context->provider_name == NULL ||
129 *proxy_context->provider_name == 0) {
130 logger_noformat(proxy_context, LOG_ERR, "Provider name required");
131 exit(1);
133 if (proxy_context->provider_publickey_s == NULL) {
134 logger_noformat(proxy_context, LOG_ERR, "Provider key required");
135 exit(1);
137 if (dnscrypt_fingerprint_to_key(proxy_context->provider_publickey_s,
138 proxy_context->provider_publickey) != 0) {
139 logger_noformat(proxy_context, LOG_ERR, "Invalid provider key");
140 exit(1);
142 if (proxy_context->daemonize) {
143 do_daemonize();
145 #ifndef _WIN32
146 if (proxy_context->pid_file != NULL &&
147 pid_file_create(proxy_context->pid_file,
148 proxy_context->user_id != (uid_t) 0) != 0) {
149 logger_error(proxy_context, "Unable to create pid file");
151 #endif
152 if (proxy_context->log_file != NULL &&
153 (proxy_context->log_fd = open(proxy_context->log_file,
154 O_WRONLY | O_APPEND | O_CREAT,
155 (mode_t) 0600)) == -1) {
156 logger_error(proxy_context, "Unable to open log file");
157 exit(1);
159 if (proxy_context->log_fd == -1 && proxy_context->daemonize) {
160 logger_open_syslog(proxy_context);
162 return 0;
166 options_parse(AppContext * const app_context,
167 ProxyContext * const proxy_context, int argc, char *argv[])
169 int opt_flag;
170 int option_index = 0;
172 options_init_with_default(app_context, proxy_context);
173 while ((opt_flag = getopt_long(argc, argv,
174 getopt_options, getopt_long_options,
175 &option_index)) != -1) {
176 switch (opt_flag) {
177 case 'a':
178 proxy_context->local_ip = optarg;
179 break;
180 case 'd':
181 proxy_context->daemonize = 1;
182 break;
183 case 'e': {
184 char *endptr;
185 const unsigned long edns_payload_size = strtoul(optarg, &endptr, 10);
187 if (*optarg == 0 || *endptr != 0 ||
188 edns_payload_size > DNS_MAX_PACKET_SIZE_UDP_RECV) {
189 logger(proxy_context, LOG_ERR,
190 "Invalid EDNS payload size: [%s]", optarg);
191 exit(1);
193 if (edns_payload_size <= DNS_MAX_PACKET_SIZE_UDP_SEND) {
194 proxy_context->edns_payload_size = (size_t) 0U;
195 } else {
196 proxy_context->edns_payload_size = (size_t) edns_payload_size;
198 break;
200 case 'h':
201 options_usage();
202 exit(0);
203 case 'k':
204 proxy_context->provider_publickey_s = optarg;
205 break;
206 case 'l':
207 proxy_context->log_file = optarg;
208 break;
209 case 'n': {
210 char *endptr;
211 const unsigned long connections_count_max =
212 strtoul(optarg, &endptr, 10);
214 if (*optarg == 0 || *endptr != 0 ||
215 connections_count_max <= 0U ||
216 connections_count_max > UINT_MAX) {
217 logger(proxy_context, LOG_ERR,
218 "Invalid max number of active request: [%s]", optarg);
219 exit(1);
221 proxy_context->connections_count_max =
222 (unsigned int) connections_count_max;
223 break;
225 case 'p':
226 proxy_context->pid_file = optarg;
227 break;
228 case 'r':
229 proxy_context->resolver_ip = optarg;
230 break;
231 case 't':
232 proxy_context->resolver_port = optarg;
233 break;
234 #ifdef HAVE_GETPWNAM
235 case 'u': {
236 const struct passwd * const pw = getpwnam(optarg);
237 if (pw == NULL) {
238 logger(proxy_context, LOG_ERR, "Unknown user: [%s]", optarg);
239 exit(1);
241 proxy_context->user_id = pw->pw_uid;
242 proxy_context->user_group = pw->pw_gid;
243 proxy_context->user_dir = strdup(pw->pw_dir);
244 break;
246 #endif
247 case 'N':
248 proxy_context->provider_name = optarg;
249 break;
250 case 'P':
251 proxy_context->local_port = optarg;
252 break;
253 case 'T':
254 proxy_context->tcp_only = 1;
255 break;
256 case 'V':
257 options_version();
258 exit(0);
259 default:
260 options_usage();
261 exit(1);
264 options_apply(proxy_context);
266 return 0;
269 void
270 options_free(ProxyContext * const proxy_context)
272 free(proxy_context->user_dir);
273 proxy_context->user_dir = NULL;