Changes to update Tomato RAF.
[tomato.git] / release / src / router / dnscrypt / src / proxy / udp_request.c
blob57b32b313530e89ed0e8da8339626c57cd786b69
2 #include <config.h>
3 #include <sys/types.h>
4 #ifdef _WIN32
5 # include <winsock2.h>
6 #else
7 # include <sys/socket.h>
8 # include <arpa/inet.h>
9 # include <netinet/in.h>
10 #endif
12 #include <assert.h>
13 #include <errno.h>
14 #include <limits.h>
15 #include <stdlib.h>
16 #include <string.h>
18 #include <event2/event.h>
19 #include <event2/util.h>
21 #include "dnscrypt_client.h"
22 #include "dnscrypt_proxy.h"
23 #include "edns.h"
24 #include "logger.h"
25 #include "probes.h"
26 #include "queue.h"
27 #include "tcp_request.h"
28 #include "udp_request.h"
29 #include "udp_request_p.h"
30 #include "utils.h"
32 static void
33 udp_request_free(UDPRequest * const udp_request)
35 ProxyContext *proxy_context;
37 if (udp_request->sendto_retry_timer != NULL) {
38 free(event_get_callback_arg(udp_request->sendto_retry_timer));
39 event_free(udp_request->sendto_retry_timer);
40 udp_request->sendto_retry_timer = NULL;
42 if (udp_request->timeout_timer != NULL) {
43 event_free(udp_request->timeout_timer);
44 udp_request->timeout_timer = NULL;
46 DNSCRYPT_PROXY_REQUEST_UDP_DONE(udp_request);
47 proxy_context = udp_request->proxy_context;
48 if (udp_request->status.is_in_queue != 0) {
49 assert(! TAILQ_EMPTY(&proxy_context->udp_request_queue));
50 TAILQ_REMOVE(&proxy_context->udp_request_queue, udp_request, queue);
51 assert(proxy_context->connections_count > 0U);
52 proxy_context->connections_count--;
53 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
54 proxy_context->connections_count_max);
56 udp_request->proxy_context = NULL;
57 free(udp_request);
60 static void
61 udp_request_kill(UDPRequest * const udp_request)
63 if (udp_request == NULL || udp_request->status.is_dying) {
64 return;
66 udp_request->status.is_dying = 1;
67 udp_request_free(udp_request);
70 static int sendto_with_retry(SendtoWithRetryCtx * const ctx);
72 #ifndef UDP_REQUEST_NO_RETRIES
73 static void
74 sendto_with_retry_timer_cb(evutil_socket_t retry_timer_handle, short ev_flags,
75 void * const ctx_)
77 SendtoWithRetryCtx * const ctx = ctx_;
79 (void) ev_flags;
80 assert(retry_timer_handle ==
81 event_get_fd(ctx->udp_request->sendto_retry_timer));
83 DNSCRYPT_PROXY_REQUEST_UDP_RETRY(ctx->udp_request,
84 ctx->udp_request->retries);
85 sendto_with_retry(ctx);
87 #endif
89 static int
90 sendto_with_retry(SendtoWithRetryCtx * const ctx)
92 SendtoWithRetryCtx *ctx_cb;
93 UDPRequest *udp_request = ctx->udp_request;
94 int err;
95 _Bool retriable;
97 if (sendto(ctx->handle, ctx->buffer, ctx->length, ctx->flags,
98 ctx->dest_addr, ctx->dest_len) == (ssize_t) ctx->length) {
99 if (ctx->cb) {
100 ctx->cb(udp_request);
102 if (udp_request->sendto_retry_timer != NULL) {
103 assert(event_get_callback_arg(udp_request->sendto_retry_timer)
104 == ctx);
105 free(ctx);
106 event_free(udp_request->sendto_retry_timer);
107 udp_request->sendto_retry_timer = NULL;
109 return 0;
112 err = evutil_socket_geterror(udp_request->client_proxy_handle);
113 logger(udp_request->proxy_context, LOG_WARNING,
114 "sendto: [%s]", evutil_socket_error_to_string(err));
115 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(udp_request);
117 #ifdef UDP_REQUEST_NO_RETRIES
118 (void) ctx_cb;
119 (void) retriable;
120 udp_request_kill(udp_request);
122 return -1;
124 #else
126 # ifdef _WIN32
127 retriable = (err == WSAENOBUFS ||
128 err == WSAEWOULDBLOCK || err == WSAEINTR);
129 # else
130 retriable = (err == ENOBUFS || err == ENOMEM ||
131 err == EAGAIN || err == EINTR);
132 # endif
133 if (retriable == 0) {
134 udp_request_kill(udp_request);
135 return -1;
137 COMPILER_ASSERT(DNS_QUERY_TIMEOUT < UCHAR_MAX);
138 if (++(udp_request->retries) > DNS_QUERY_TIMEOUT) {
139 udp_request_kill(udp_request);
140 return -1;
142 if (udp_request->sendto_retry_timer != NULL) {
143 ctx_cb = event_get_callback_arg(udp_request->sendto_retry_timer);
144 assert(ctx_cb != NULL);
145 assert(ctx_cb->udp_request == ctx->udp_request);
146 assert(ctx_cb->buffer == ctx->buffer);
147 assert(ctx_cb->cb == ctx->cb);
148 } else {
149 if ((ctx_cb = malloc(sizeof *ctx_cb)) == NULL) {
150 logger_error(udp_request->proxy_context, "malloc");
151 udp_request_kill(udp_request);
152 return -1;
154 if ((udp_request->sendto_retry_timer =
155 evtimer_new(udp_request->proxy_context->event_loop,
156 sendto_with_retry_timer_cb, ctx_cb)) == NULL) {
157 free(ctx_cb);
158 udp_request_kill(udp_request);
159 return -1;
161 assert(ctx_cb ==
162 event_get_callback_arg(udp_request->sendto_retry_timer));
163 *ctx_cb = *ctx;
165 const struct timeval tv = {
166 .tv_sec = (time_t) UDP_DELAY_BETWEEN_RETRIES, .tv_usec = 0
168 evtimer_add(udp_request->sendto_retry_timer, &tv);
169 DNSCRYPT_PROXY_REQUEST_UDP_RETRY_SCHEDULED(udp_request,
170 udp_request->retries);
171 return -1;
172 #endif
175 static void
176 resolver_to_proxy_cb(evutil_socket_t proxy_resolver_handle, short ev_flags,
177 void * const proxy_context_)
179 uint8_t dns_packet[DNS_MAX_PACKET_SIZE_UDP];
180 ProxyContext *proxy_context = proxy_context_;
181 UDPRequest *scanned_udp_request;
182 UDPRequest *udp_request = NULL;
183 struct sockaddr_storage resolver_sockaddr;
184 ev_socklen_t resolver_sockaddr_len = sizeof resolver_sockaddr;
185 ssize_t nread;
186 size_t dns_packet_len = (size_t) 0U;
187 size_t uncurved_len;
189 (void) ev_flags;
190 nread = recvfrom(proxy_resolver_handle,
191 (void *) dns_packet, sizeof dns_packet, 0,
192 (struct sockaddr *) &resolver_sockaddr,
193 &resolver_sockaddr_len);
194 if (nread < (ssize_t) 0) {
195 const int err = evutil_socket_geterror(proxy_resolver_handle);
196 logger(proxy_context, LOG_WARNING,
197 "recvfrom(resolver): [%s]", evutil_socket_error_to_string(err));
198 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(NULL);
199 return;
201 if (evutil_sockaddr_cmp((const struct sockaddr *) &resolver_sockaddr,
202 (const struct sockaddr *)
203 &proxy_context->resolver_sockaddr, 1) != 0) {
204 logger_noformat(proxy_context, LOG_WARNING,
205 "Received a resolver reply from a different resolver");
206 return;
208 TAILQ_FOREACH(scanned_udp_request,
209 &proxy_context->udp_request_queue, queue) {
210 if (dnscrypt_cmp_client_nonce(scanned_udp_request->client_nonce,
211 dns_packet, (size_t) nread) == 0) {
212 udp_request = scanned_udp_request;
213 break;
216 if (udp_request == NULL) {
217 logger(proxy_context, LOG_DEBUG,
218 "Received a reply that doesn't match any active query");
219 return;
221 if (nread < (ssize_t) (DNS_HEADER_SIZE + dnscrypt_response_header_size()) ||
222 nread > (ssize_t) sizeof dns_packet) {
223 udp_request_kill(udp_request);
224 return;
226 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_REPLIED(udp_request);
227 dns_packet_len = (size_t) nread;
228 assert(dns_packet_len <= sizeof dns_packet);
230 uncurved_len = dns_packet_len;
231 DNSCRYPT_PROXY_REQUEST_UNCURVE_START(udp_request, uncurved_len);
232 if (dnscrypt_client_uncurve
233 (&udp_request->proxy_context->dnscrypt_client,
234 udp_request->client_nonce, dns_packet, &uncurved_len) != 0) {
235 DNSCRYPT_PROXY_REQUEST_UNCURVE_ERROR(udp_request);
236 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_GOT_INVALID_REPLY(udp_request);
237 logger_noformat(udp_request->proxy_context, LOG_WARNING,
238 "Received a suspicious reply from the resolver");
239 udp_request_kill(udp_request);
240 return;
242 DNSCRYPT_PROXY_REQUEST_UNCURVE_DONE(udp_request, uncurved_len);
243 memset(udp_request->client_nonce, 0, sizeof udp_request->client_nonce);
244 assert(uncurved_len <= dns_packet_len);
245 dns_packet_len = uncurved_len;
246 sendto_with_retry(& (SendtoWithRetryCtx) {
247 .udp_request = udp_request,
248 .handle = udp_request->client_proxy_handle,
249 .buffer = dns_packet,
250 .length = dns_packet_len,
251 .flags = 0,
252 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
253 .dest_len = udp_request->client_sockaddr_len,
254 .cb = udp_request_kill
258 static void
259 proxy_client_send_truncated(UDPRequest * const udp_request,
260 uint8_t dns_packet[DNS_MAX_PACKET_SIZE_UDP],
261 size_t dns_packet_len)
263 DNSCRYPT_PROXY_REQUEST_UDP_TRUNCATED(udp_request);
265 assert(dns_packet_len > DNS_OFFSET_FLAGS2);
266 dns_packet[DNS_OFFSET_FLAGS] |= DNS_FLAGS_TC | DNS_FLAGS_QR;
267 dns_packet[DNS_OFFSET_FLAGS2] |= DNS_FLAGS2_RA;
268 sendto_with_retry(& (SendtoWithRetryCtx) {
269 .udp_request = udp_request,
270 .handle = udp_request->client_proxy_handle,
271 .buffer = dns_packet,
272 .length = dns_packet_len,
273 .flags = 0,
274 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
275 .dest_len = udp_request->client_sockaddr_len,
276 .cb = udp_request_kill
280 static void
281 timeout_timer_cb(evutil_socket_t timeout_timer_handle, short ev_flags,
282 void * const udp_request_)
284 UDPRequest * const udp_request = udp_request_;
286 (void) ev_flags;
287 (void) timeout_timer_handle;
288 DNSCRYPT_PROXY_REQUEST_UDP_TIMEOUT(udp_request);
289 logger_noformat(udp_request->proxy_context, LOG_DEBUG,
290 "resolver timeout (UDP)");
291 udp_request_kill(udp_request);
294 #ifndef SO_RCVBUFFORCE
295 # define SO_RCVBUFFORCE SO_RCVBUF
296 #endif
297 #ifndef SO_SNDBUFFORCE
298 # define SO_SNDBUFFORCE SO_SNDBUF
299 #endif
301 static void
302 udp_tune(evutil_socket_t const handle)
304 if (handle == -1) {
305 return;
307 setsockopt(handle, SOL_SOCKET, SO_RCVBUFFORCE,
308 (void *) (int []) { UDP_BUFFER_SIZE }, sizeof (int));
309 setsockopt(handle, SOL_SOCKET, SO_SNDBUFFORCE,
310 (void *) (int []) { UDP_BUFFER_SIZE }, sizeof (int));
311 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
312 setsockopt(handle, IPPROTO_IP, IP_MTU_DISCOVER,
313 (void *) (int []) { IP_PMTUDISC_DONT }, sizeof (int));
314 #elif defined(IP_DONTFRAG)
315 setsockopt(handle, IPPROTO_IP, IP_DONTFRAG,
316 (void *) (int []) { 0 }, sizeof (int));
317 #endif
320 static void
321 client_to_proxy_cb_sendto_cb(UDPRequest * const udp_request)
323 (void) udp_request;
324 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_START(udp_request);
327 static void
328 client_to_proxy_cb(evutil_socket_t client_proxy_handle, short ev_flags,
329 void * const proxy_context_)
331 uint8_t dns_packet[DNS_MAX_PACKET_SIZE_UDP];
332 ProxyContext *proxy_context = proxy_context_;
333 UDPRequest *udp_request;
334 ssize_t curve_ret;
335 ssize_t nread;
336 size_t dns_packet_len = (size_t) 0U;
337 size_t max_packet_size;
338 size_t request_edns_payload_size;
340 (void) ev_flags;
341 assert(client_proxy_handle == proxy_context->udp_listener_handle);
342 if ((udp_request = calloc((size_t) 1U, sizeof *udp_request)) == NULL) {
343 return;
345 udp_request->proxy_context = proxy_context;
346 udp_request->sendto_retry_timer = NULL;
347 udp_request->timeout_timer = NULL;
348 udp_request->client_proxy_handle = client_proxy_handle;
349 udp_request->client_sockaddr_len = sizeof udp_request->client_sockaddr;
350 nread = recvfrom(client_proxy_handle,
351 (void *) dns_packet, sizeof dns_packet, 0,
352 (struct sockaddr *) &udp_request->client_sockaddr,
353 &udp_request->client_sockaddr_len);
354 if (nread < (ssize_t) 0) {
355 const int err = evutil_socket_geterror(client_proxy_handle);
356 logger(proxy_context, LOG_WARNING,
357 "recvfrom(client): [%s]", evutil_socket_error_to_string(err));
358 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(udp_request);
359 udp_request_kill(udp_request);
360 return;
362 if (nread < (ssize_t) DNS_HEADER_SIZE ||
363 (size_t) nread > sizeof dns_packet) {
364 logger_noformat(proxy_context, LOG_WARNING, "Short query received");
365 free(udp_request);
366 return;
368 if (proxy_context->connections_count >=
369 proxy_context->connections_count_max) {
370 DNSCRYPT_PROXY_REQUEST_UDP_OVERLOADED();
371 if (udp_listener_kill_oldest_request(proxy_context) != 0) {
372 tcp_listener_kill_oldest_request(proxy_context);
375 proxy_context->connections_count++;
376 assert(proxy_context->connections_count
377 <= proxy_context->connections_count_max);
378 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
379 proxy_context->connections_count_max);
380 DNSCRYPT_PROXY_REQUEST_UDP_START(udp_request);
381 TAILQ_INSERT_TAIL(&proxy_context->udp_request_queue,
382 udp_request, queue);
383 memset(&udp_request->status, 0, sizeof udp_request->status);
384 udp_request->status.is_in_queue = 1;
386 dns_packet_len = (size_t) nread;
387 assert(dns_packet_len <= sizeof dns_packet);
389 edns_add_section(proxy_context, dns_packet, &dns_packet_len,
390 sizeof dns_packet, &request_edns_payload_size);
392 if (request_edns_payload_size < DNS_MAX_PACKET_SIZE_UDP_SEND) {
393 max_packet_size = DNS_MAX_PACKET_SIZE_UDP_SEND;
394 } else {
395 max_packet_size = request_edns_payload_size;
397 if (max_packet_size > sizeof dns_packet) {
398 max_packet_size = sizeof dns_packet;
400 assert(max_packet_size <= sizeof dns_packet);
401 assert(SIZE_MAX - DNSCRYPT_MAX_PADDING - dnscrypt_query_header_size()
402 > dns_packet_len);
403 size_t max_len = dns_packet_len + DNSCRYPT_MAX_PADDING +
404 dnscrypt_query_header_size();
405 if (max_len > max_packet_size) {
406 max_len = max_packet_size;
408 if (udp_request->proxy_context->tcp_only != 0 ||
409 dns_packet_len + dnscrypt_query_header_size() > max_len) {
410 proxy_client_send_truncated(udp_request, dns_packet, dns_packet_len);
411 return;
413 DNSCRYPT_PROXY_REQUEST_CURVE_START(udp_request, dns_packet_len);
414 curve_ret =
415 dnscrypt_client_curve(&udp_request->proxy_context->dnscrypt_client,
416 udp_request->client_nonce, dns_packet,
417 dns_packet_len, max_len);
418 if (curve_ret <= (ssize_t) 0) {
419 DNSCRYPT_PROXY_REQUEST_CURVE_ERROR(udp_request);
420 return;
422 dns_packet_len = (size_t) curve_ret;
423 assert(dns_packet_len >= dnscrypt_query_header_size());
424 DNSCRYPT_PROXY_REQUEST_CURVE_DONE(udp_request, dns_packet_len);
425 assert(dns_packet_len <= sizeof dns_packet);
427 udp_request->timeout_timer =
428 evtimer_new(udp_request->proxy_context->event_loop,
429 timeout_timer_cb, udp_request);
430 if (udp_request->timeout_timer != NULL) {
431 const struct timeval tv = {
432 .tv_sec = (time_t) DNS_QUERY_TIMEOUT, .tv_usec = 0
434 evtimer_add(udp_request->timeout_timer, &tv);
436 sendto_with_retry(& (SendtoWithRetryCtx) {
437 .udp_request = udp_request,
438 .handle = proxy_context->udp_proxy_resolver_handle,
439 .buffer = dns_packet,
440 .length = dns_packet_len,
441 .flags = 0,
442 .dest_addr = (struct sockaddr *) &proxy_context->resolver_sockaddr,
443 .dest_len = proxy_context->resolver_sockaddr_len,
444 .cb = client_to_proxy_cb_sendto_cb
449 udp_listener_kill_oldest_request(ProxyContext * const proxy_context)
451 if (TAILQ_EMPTY(&proxy_context->udp_request_queue)) {
452 return -1;
454 udp_request_kill(TAILQ_FIRST(&proxy_context->udp_request_queue));
456 return 0;
460 udp_listener_bind(ProxyContext * const proxy_context)
462 assert(proxy_context->udp_listener_handle == -1);
463 if ((proxy_context->udp_listener_handle = socket
464 (proxy_context->local_sockaddr.ss_family,
465 SOCK_DGRAM, IPPROTO_UDP)) == -1) {
466 logger(NULL, LOG_ERR, "Unable to create a socket (UDP)");
467 return -1;
469 evutil_make_socket_closeonexec(proxy_context->udp_listener_handle);
470 evutil_make_socket_nonblocking(proxy_context->udp_listener_handle);
471 if (bind(proxy_context->udp_listener_handle,
472 (struct sockaddr *) &proxy_context->local_sockaddr,
473 proxy_context->local_sockaddr_len) != 0) {
474 logger(NULL, LOG_ERR, "Unable to bind (UDP) [%s]",
475 evutil_socket_error_to_string
476 (evutil_socket_geterror(proxy_context->udp_listener_handle)));
477 evutil_closesocket(proxy_context->udp_listener_handle);
478 proxy_context->udp_listener_handle = -1;
479 return -1;
481 udp_tune(proxy_context->udp_listener_handle);
483 if ((proxy_context->udp_proxy_resolver_handle = socket
484 (proxy_context->resolver_sockaddr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
485 logger_noformat(proxy_context, LOG_ERR,
486 "Unable to create a socket to the resolver");
487 evutil_closesocket(proxy_context->udp_listener_handle);
488 proxy_context->udp_listener_handle = -1;
489 return -1;
491 evutil_make_socket_closeonexec(proxy_context->udp_proxy_resolver_handle);
492 evutil_make_socket_nonblocking(proxy_context->udp_proxy_resolver_handle);
493 udp_tune(proxy_context->udp_proxy_resolver_handle);
495 TAILQ_INIT(&proxy_context->udp_request_queue);
497 return 0;
501 udp_listener_start(ProxyContext * const proxy_context)
503 assert(proxy_context->udp_listener_handle != -1);
504 if ((proxy_context->udp_listener_event =
505 event_new(proxy_context->event_loop,
506 proxy_context->udp_listener_handle, EV_READ | EV_PERSIST,
507 client_to_proxy_cb, proxy_context)) == NULL) {
508 return -1;
510 if (event_add(proxy_context->udp_listener_event, NULL) != 0) {
511 udp_listener_stop(proxy_context);
512 return -1;
515 assert(proxy_context->udp_proxy_resolver_handle != -1);
516 if ((proxy_context->udp_proxy_resolver_event =
517 event_new(proxy_context->event_loop,
518 proxy_context->udp_proxy_resolver_handle,
519 EV_READ | EV_PERSIST,
520 resolver_to_proxy_cb, proxy_context)) == NULL) {
521 udp_listener_stop(proxy_context);
522 return -1;
524 if (event_add(proxy_context->udp_proxy_resolver_event, NULL) != 0) {
525 udp_listener_stop(proxy_context);
526 return -1;
528 return 0;
531 void
532 udp_listener_stop(ProxyContext * const proxy_context)
534 event_free(proxy_context->udp_proxy_resolver_event);
535 proxy_context->udp_proxy_resolver_event = NULL;
536 while (udp_listener_kill_oldest_request(proxy_context) != 0) { }
537 logger_noformat(proxy_context, LOG_INFO, "UDP listener shut down");