dnscrypt-proxy 1.6.0
[tomato.git] / release / src / router / dnscrypt / src / proxy / udp_request.c
bloba6a347ee668065939bf1ba8b28182f19e9fbfc3f
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 <stdint.h>
16 #include <stdlib.h>
17 #include <string.h>
19 #include <event2/event.h>
20 #include <event2/util.h>
22 #include "dnscrypt_client.h"
23 #include "dnscrypt_proxy.h"
24 #include "edns.h"
25 #include "logger.h"
26 #include "probes.h"
27 #include "queue.h"
28 #include "tcp_request.h"
29 #include "udp_request.h"
30 #include "udp_request_p.h"
31 #include "utils.h"
32 #ifdef PLUGINS
33 # include "plugin_support.h"
34 #endif
36 static void
37 udp_request_free(UDPRequest * const udp_request)
39 ProxyContext *proxy_context;
41 if (udp_request->timeout_timer != NULL) {
42 event_free(udp_request->timeout_timer);
43 udp_request->timeout_timer = NULL;
45 DNSCRYPT_PROXY_REQUEST_UDP_DONE(udp_request);
46 proxy_context = udp_request->proxy_context;
47 if (udp_request->status.is_in_queue != 0) {
48 assert(! TAILQ_EMPTY(&proxy_context->udp_request_queue));
49 TAILQ_REMOVE(&proxy_context->udp_request_queue, udp_request, queue);
50 assert(proxy_context->connections_count > 0U);
51 proxy_context->connections_count--;
52 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
53 proxy_context->connections_count_max);
55 udp_request->proxy_context = NULL;
56 free(udp_request);
59 static void
60 udp_request_kill(UDPRequest * const udp_request)
62 if (udp_request == NULL || udp_request->status.is_dying) {
63 return;
65 udp_request->status.is_dying = 1;
66 udp_request_free(udp_request);
69 static int udp_send(SendtoWithRetryCtx * const ctx);
71 static int
72 udp_send(SendtoWithRetryCtx * const ctx)
74 void (*cb)(UDPRequest *udp_request);
75 UDPRequest *udp_request = ctx->udp_request;
77 (void) sendto(ctx->handle, ctx->buffer, ctx->length, ctx->flags,
78 ctx->dest_addr, ctx->dest_len);
79 cb = ctx->cb;
80 if (cb) {
81 cb(udp_request);
83 return 0;
86 static void
87 resolver_to_proxy_cb(evutil_socket_t proxy_resolver_handle, short ev_flags,
88 void * const proxy_context_)
90 uint8_t dns_reply[DNS_MAX_PACKET_SIZE_UDP];
91 ProxyContext *proxy_context = proxy_context_;
92 UDPRequest *scanned_udp_request;
93 UDPRequest *udp_request = NULL;
94 struct sockaddr_storage resolver_sockaddr;
95 ev_socklen_t resolver_sockaddr_len = sizeof resolver_sockaddr;
96 ssize_t nread;
97 size_t dns_reply_len = (size_t) 0U;
98 size_t uncurved_len;
100 (void) ev_flags;
101 nread = recvfrom(proxy_resolver_handle,
102 (void *) dns_reply, sizeof dns_reply, 0,
103 (struct sockaddr *) &resolver_sockaddr,
104 &resolver_sockaddr_len);
105 if (nread < (ssize_t) 0) {
106 const int err = evutil_socket_geterror(proxy_resolver_handle);
107 if (!EVUTIL_ERR_RW_RETRIABLE(err)) {
108 logger(proxy_context, LOG_WARNING,
109 "recvfrom(resolver): [%s]", evutil_socket_error_to_string(err));
111 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(NULL);
112 return;
114 if (evutil_sockaddr_cmp((const struct sockaddr *) &resolver_sockaddr,
115 (const struct sockaddr *)
116 &proxy_context->resolver_sockaddr, 1) != 0) {
117 logger_noformat(proxy_context, LOG_DEBUG,
118 "Received a resolver reply from a different resolver");
119 return;
121 TAILQ_FOREACH(scanned_udp_request,
122 &proxy_context->udp_request_queue, queue) {
123 if (dnscrypt_cmp_client_nonce(scanned_udp_request->client_nonce,
124 dns_reply, (size_t) nread) == 0) {
125 udp_request = scanned_udp_request;
126 break;
129 if (udp_request == NULL) {
130 logger(proxy_context, LOG_DEBUG,
131 "Received a reply that doesn't match any active query");
132 return;
134 if (nread < (ssize_t) (DNS_HEADER_SIZE + dnscrypt_response_header_size()) ||
135 nread > (ssize_t) sizeof dns_reply) {
136 logger_noformat(proxy_context, LOG_WARNING, "Short reply received");
137 udp_request_kill(udp_request);
138 return;
140 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_REPLIED(udp_request);
141 dns_reply_len = (size_t) nread;
142 assert(dns_reply_len <= sizeof dns_reply);
144 uncurved_len = dns_reply_len;
145 DNSCRYPT_PROXY_REQUEST_UNCURVE_START(udp_request, uncurved_len);
146 if (dnscrypt_client_uncurve
147 (&udp_request->proxy_context->dnscrypt_client,
148 udp_request->client_nonce, dns_reply, &uncurved_len) != 0) {
149 DNSCRYPT_PROXY_REQUEST_UNCURVE_ERROR(udp_request);
150 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_GOT_INVALID_REPLY(udp_request);
151 logger_noformat(udp_request->proxy_context, LOG_WARNING,
152 "Received a suspicious reply from the resolver");
153 udp_request_kill(udp_request);
154 return;
156 DNSCRYPT_PROXY_REQUEST_UNCURVE_DONE(udp_request, uncurved_len);
157 memset(udp_request->client_nonce, 0, sizeof udp_request->client_nonce);
158 assert(uncurved_len <= dns_reply_len);
159 dns_reply_len = uncurved_len;
161 assert(dns_reply_len >= DNS_HEADER_SIZE);
162 COMPILER_ASSERT(DNS_OFFSET_FLAGS < DNS_HEADER_SIZE);
163 if ((dns_reply[DNS_OFFSET_FLAGS] & DNS_FLAGS_TC) != 0) {
164 if (proxy_context->udp_current_max_size <
165 proxy_context->udp_max_size) {
166 COMPILER_ASSERT(DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND >=
167 DNSCRYPT_BLOCK_SIZE);
168 if (proxy_context->udp_max_size -
169 proxy_context->udp_current_max_size > DNSCRYPT_BLOCK_SIZE) {
170 proxy_context->udp_current_max_size += DNSCRYPT_BLOCK_SIZE;
171 } else {
172 proxy_context->udp_current_max_size =
173 proxy_context->udp_max_size;
178 #ifdef PLUGINS
179 const size_t max_reply_size_for_filter = sizeof dns_reply;
180 DCPluginDNSPacket dcp_packet = {
181 .client_sockaddr = &udp_request->client_sockaddr,
182 .dns_packet = dns_reply,
183 .dns_packet_len_p = &dns_reply_len,
184 .client_sockaddr_len_s = (size_t) udp_request->client_sockaddr_len,
185 .dns_packet_max_len = max_reply_size_for_filter
187 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_START(udp_request, dns_reply_len,
188 max_reply_size_for_filter);
189 assert(proxy_context->app_context->dcps_context != NULL);
190 const DCPluginSyncFilterResult res =
191 plugin_support_context_apply_sync_post_filters
192 (proxy_context->app_context->dcps_context, &dcp_packet);
193 assert(dns_reply_len > (size_t) 0U &&
194 dns_reply_len <= sizeof dns_reply &&
195 dns_reply_len <= max_reply_size_for_filter);
196 if (res != DCP_SYNC_FILTER_RESULT_OK) {
197 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_ERROR(udp_request, res);
198 udp_request_kill(udp_request);
199 return;
201 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_DONE(udp_request, dns_reply_len,
202 max_reply_size_for_filter);
203 #endif
204 udp_send(& (SendtoWithRetryCtx) {
205 .udp_request = udp_request,
206 .handle = udp_request->client_proxy_handle,
207 .buffer = dns_reply,
208 .length = dns_reply_len,
209 .flags = 0,
210 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
211 .dest_len = udp_request->client_sockaddr_len,
212 .cb = udp_request_kill
216 static void
217 proxy_client_send_truncated(UDPRequest * const udp_request,
218 uint8_t dns_reply[DNS_MAX_PACKET_SIZE_UDP],
219 size_t dns_reply_len)
221 DNSCRYPT_PROXY_REQUEST_UDP_TRUNCATED(udp_request);
223 assert(dns_reply_len > DNS_OFFSET_FLAGS2);
224 dns_reply[DNS_OFFSET_FLAGS] |= DNS_FLAGS_TC | DNS_FLAGS_QR;
225 dns_reply[DNS_OFFSET_FLAGS2] |= DNS_FLAGS2_RA;
226 udp_send(& (SendtoWithRetryCtx) {
227 .udp_request = udp_request,
228 .handle = udp_request->client_proxy_handle,
229 .buffer = dns_reply,
230 .length = dns_reply_len,
231 .flags = 0,
232 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
233 .dest_len = udp_request->client_sockaddr_len,
234 .cb = udp_request_kill
238 static void
239 timeout_timer_cb(evutil_socket_t timeout_timer_handle, short ev_flags,
240 void * const udp_request_)
242 UDPRequest * const udp_request = udp_request_;
244 (void) ev_flags;
245 (void) timeout_timer_handle;
246 DNSCRYPT_PROXY_REQUEST_UDP_TIMEOUT(udp_request);
247 logger_noformat(udp_request->proxy_context, LOG_DEBUG,
248 "resolver timeout (UDP)");
249 udp_request_kill(udp_request);
252 #ifndef SO_RCVBUFFORCE
253 # define SO_RCVBUFFORCE SO_RCVBUF
254 #endif
255 #ifndef SO_SNDBUFFORCE
256 # define SO_SNDBUFFORCE SO_SNDBUF
257 #endif
259 static void
260 udp_tune(evutil_socket_t const handle)
262 if (handle == -1) {
263 return;
265 setsockopt(handle, SOL_SOCKET, SO_RCVBUFFORCE,
266 (void *) (int []) { UDP_BUFFER_SIZE }, sizeof (int));
267 setsockopt(handle, SOL_SOCKET, SO_SNDBUFFORCE,
268 (void *) (int []) { UDP_BUFFER_SIZE }, sizeof (int));
269 #if defined(IP_PMTUDISC_OMIT)
270 setsockopt(handle, IPPROTO_IP, IP_MTU_DISCOVER,
271 (void *) (int []) { IP_PMTUDISC_OMIT }, sizeof (int));
272 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
273 setsockopt(handle, IPPROTO_IP, IP_MTU_DISCOVER,
274 (void *) (int []) { IP_PMTUDISC_DONT }, sizeof (int));
275 #elif defined(IP_DONTFRAG)
276 setsockopt(handle, IPPROTO_IP, IP_DONTFRAG,
277 (void *) (int []) { 0 }, sizeof (int));
278 #endif
281 static void
282 client_to_proxy_cb_sendto_cb(UDPRequest * const udp_request)
284 (void) udp_request;
285 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_START(udp_request);
288 #ifdef PLUGINS
289 static void
290 proxy_to_client_direct(UDPRequest * const udp_request,
291 const uint8_t * const dns_reply,
292 const size_t dns_reply_len)
294 udp_send(& (SendtoWithRetryCtx) {
295 .udp_request = udp_request,
296 .handle = udp_request->client_proxy_handle,
297 .buffer = dns_reply,
298 .length = dns_reply_len,
299 .flags = 0,
300 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
301 .dest_len = udp_request->client_sockaddr_len,
302 .cb = udp_request_kill
305 #endif
307 static void
308 client_to_proxy_cb(evutil_socket_t client_proxy_handle, short ev_flags,
309 void * const proxy_context_)
311 uint8_t dns_query[DNS_MAX_PACKET_SIZE_UDP];
312 ProxyContext *proxy_context = proxy_context_;
313 UDPRequest *udp_request;
314 ssize_t curve_ret;
315 ssize_t nread;
316 size_t dns_query_len = (size_t) 0U;
317 size_t max_query_size;
318 size_t request_edns_payload_size;
320 (void) ev_flags;
321 assert(client_proxy_handle == proxy_context->udp_listener_handle);
322 if ((udp_request = calloc((size_t) 1U, sizeof *udp_request)) == NULL) {
323 return;
325 udp_request->proxy_context = proxy_context;
326 udp_request->timeout_timer = NULL;
327 udp_request->client_proxy_handle = client_proxy_handle;
328 udp_request->client_sockaddr_len = sizeof udp_request->client_sockaddr;
329 nread = recvfrom(client_proxy_handle,
330 (void *) dns_query, sizeof dns_query, 0,
331 (struct sockaddr *) &udp_request->client_sockaddr,
332 &udp_request->client_sockaddr_len);
333 if (nread < (ssize_t) 0) {
334 const int err = evutil_socket_geterror(client_proxy_handle);
335 if (!EVUTIL_ERR_RW_RETRIABLE(err)) {
336 logger(proxy_context, LOG_WARNING,
337 "recvfrom(client): [%s]", evutil_socket_error_to_string(err));
339 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(udp_request);
340 udp_request_kill(udp_request);
341 return;
343 if (nread < (ssize_t) DNS_HEADER_SIZE ||
344 (size_t) nread > sizeof dns_query) {
345 logger_noformat(proxy_context, LOG_WARNING, "Short query received");
346 free(udp_request);
347 return;
349 if (proxy_context->connections_count >=
350 proxy_context->connections_count_max) {
351 DNSCRYPT_PROXY_REQUEST_UDP_OVERLOADED();
352 if (udp_listener_kill_oldest_request(proxy_context) != 0) {
353 tcp_listener_kill_oldest_request(proxy_context);
356 proxy_context->connections_count++;
357 assert(proxy_context->connections_count
358 <= proxy_context->connections_count_max);
359 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
360 proxy_context->connections_count_max);
361 DNSCRYPT_PROXY_REQUEST_UDP_START(udp_request);
362 TAILQ_INSERT_TAIL(&proxy_context->udp_request_queue,
363 udp_request, queue);
364 memset(&udp_request->status, 0, sizeof udp_request->status);
365 udp_request->status.is_in_queue = 1;
367 dns_query_len = (size_t) nread;
368 assert(dns_query_len <= sizeof dns_query);
370 edns_add_section(proxy_context, dns_query, &dns_query_len,
371 sizeof dns_query, &request_edns_payload_size);
373 if (request_edns_payload_size < DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND) {
374 max_query_size = DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND;
375 } else {
376 max_query_size = request_edns_payload_size;
378 if (max_query_size > sizeof dns_query) {
379 max_query_size = sizeof dns_query;
381 assert(max_query_size <= sizeof dns_query);
382 if (udp_request->proxy_context->tcp_only != 0) {
383 proxy_client_send_truncated(udp_request, dns_query, dns_query_len);
384 return;
386 #ifdef PLUGINS
387 size_t max_query_size_for_filter = dns_query_len;
388 if (max_query_size > DNSCRYPT_MAX_PADDING + dnscrypt_query_header_size()) {
389 max_query_size_for_filter = max_query_size -
390 (DNSCRYPT_MAX_PADDING + dnscrypt_query_header_size());
392 DCPluginDNSPacket dcp_packet = {
393 .client_sockaddr = &udp_request->client_sockaddr,
394 .dns_packet = dns_query,
395 .dns_packet_len_p = &dns_query_len,
396 .client_sockaddr_len_s = (size_t) udp_request->client_sockaddr_len,
397 .dns_packet_max_len = max_query_size_for_filter
399 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_START(udp_request, dns_query_len,
400 max_query_size_for_filter);
401 assert(proxy_context->app_context->dcps_context != NULL);
402 const DCPluginSyncFilterResult res =
403 plugin_support_context_apply_sync_pre_filters
404 (proxy_context->app_context->dcps_context, &dcp_packet);
405 assert(dns_query_len > (size_t) 0U && dns_query_len <= max_query_size &&
406 dns_query_len <= max_query_size_for_filter);
407 switch (res) {
408 case DCP_SYNC_FILTER_RESULT_OK:
409 break;
410 case DCP_SYNC_FILTER_RESULT_DIRECT:
411 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_DONE(udp_request, dns_query_len,
412 max_query_size_for_filter);
413 proxy_to_client_direct(udp_request, dns_query, dns_query_len);
414 return;
415 default:
416 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_ERROR(udp_request, res);
417 udp_request_kill(udp_request);
418 return;
420 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_DONE(udp_request, dns_query_len,
421 max_query_size_for_filter);
422 #endif
423 assert(SIZE_MAX - DNSCRYPT_MAX_PADDING - dnscrypt_query_header_size()
424 > dns_query_len);
426 size_t max_len;
427 max_len = proxy_context->udp_current_max_size;
428 if (max_len > max_query_size) {
429 max_len = max_query_size;
431 if (dns_query_len + dnscrypt_query_header_size() > max_len) {
432 proxy_client_send_truncated(udp_request, dns_query, dns_query_len);
433 return;
435 DNSCRYPT_PROXY_REQUEST_CURVE_START(udp_request, dns_query_len);
436 curve_ret =
437 dnscrypt_client_curve(&udp_request->proxy_context->dnscrypt_client,
438 udp_request->client_nonce, dns_query,
439 dns_query_len, max_len);
440 if (curve_ret <= (ssize_t) 0) {
441 DNSCRYPT_PROXY_REQUEST_CURVE_ERROR(udp_request);
442 return;
444 dns_query_len = (size_t) curve_ret;
445 assert(dns_query_len >= dnscrypt_query_header_size());
446 DNSCRYPT_PROXY_REQUEST_CURVE_DONE(udp_request, dns_query_len);
447 assert(dns_query_len <= sizeof dns_query);
449 udp_request->timeout_timer =
450 evtimer_new(udp_request->proxy_context->event_loop,
451 timeout_timer_cb, udp_request);
452 if (udp_request->timeout_timer != NULL) {
453 const struct timeval tv = {
454 .tv_sec = (time_t) DNS_QUERY_TIMEOUT, .tv_usec = 0
456 evtimer_add(udp_request->timeout_timer, &tv);
458 udp_send(& (SendtoWithRetryCtx) {
459 .udp_request = udp_request,
460 .handle = proxy_context->udp_proxy_resolver_handle,
461 .buffer = dns_query,
462 .length = dns_query_len,
463 .flags = 0,
464 .dest_addr = (struct sockaddr *) &proxy_context->resolver_sockaddr,
465 .dest_len = proxy_context->resolver_sockaddr_len,
466 .cb = client_to_proxy_cb_sendto_cb
471 udp_listener_kill_oldest_request(ProxyContext * const proxy_context)
473 if (TAILQ_EMPTY(&proxy_context->udp_request_queue)) {
474 return -1;
476 udp_request_kill(TAILQ_FIRST(&proxy_context->udp_request_queue));
478 return 0;
482 udp_listener_bind(ProxyContext * const proxy_context)
484 if (proxy_context->udp_listener_handle == -1) {
485 if ((proxy_context->udp_listener_handle = socket
486 (proxy_context->local_sockaddr.ss_family,
487 SOCK_DGRAM, IPPROTO_UDP)) == -1) {
488 logger_noformat(proxy_context, LOG_ERR,
489 "Unable to create a socket (UDP)");
490 return -1;
492 if (bind(proxy_context->udp_listener_handle,
493 (struct sockaddr *) &proxy_context->local_sockaddr,
494 proxy_context->local_sockaddr_len) != 0) {
495 logger(NULL, LOG_ERR, "Unable to bind (UDP) [%s]",
496 evutil_socket_error_to_string(evutil_socket_geterror(
497 proxy_context->udp_listener_handle)));
498 evutil_closesocket(proxy_context->udp_listener_handle);
499 proxy_context->udp_listener_handle = -1;
500 return -1;
503 evutil_make_socket_closeonexec(proxy_context->udp_listener_handle);
504 evutil_make_socket_nonblocking(proxy_context->udp_listener_handle);
505 udp_tune(proxy_context->udp_listener_handle);
507 if ((proxy_context->udp_proxy_resolver_handle = socket
508 (proxy_context->resolver_sockaddr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
509 logger_noformat(proxy_context, LOG_ERR,
510 "Unable to create a socket to the resolver");
511 evutil_closesocket(proxy_context->udp_listener_handle);
512 proxy_context->udp_listener_handle = -1;
513 return -1;
515 evutil_make_socket_closeonexec(proxy_context->udp_proxy_resolver_handle);
516 evutil_make_socket_nonblocking(proxy_context->udp_proxy_resolver_handle);
517 udp_tune(proxy_context->udp_proxy_resolver_handle);
519 TAILQ_INIT(&proxy_context->udp_request_queue);
521 return 0;
525 udp_listener_start(ProxyContext * const proxy_context)
527 assert(proxy_context->udp_listener_handle != -1);
528 if ((proxy_context->udp_listener_event =
529 event_new(proxy_context->event_loop,
530 proxy_context->udp_listener_handle, EV_READ | EV_PERSIST,
531 client_to_proxy_cb, proxy_context)) == NULL) {
532 return -1;
534 if (event_add(proxy_context->udp_listener_event, NULL) != 0) {
535 udp_listener_stop(proxy_context);
536 return -1;
539 assert(proxy_context->udp_proxy_resolver_handle != -1);
540 if ((proxy_context->udp_proxy_resolver_event =
541 event_new(proxy_context->event_loop,
542 proxy_context->udp_proxy_resolver_handle,
543 EV_READ | EV_PERSIST,
544 resolver_to_proxy_cb, proxy_context)) == NULL) {
545 udp_listener_stop(proxy_context);
546 return -1;
548 if (event_add(proxy_context->udp_proxy_resolver_event, NULL) != 0) {
549 udp_listener_stop(proxy_context);
550 return -1;
552 return 0;
555 void
556 udp_listener_stop(ProxyContext * const proxy_context)
558 event_free(proxy_context->udp_proxy_resolver_event);
559 proxy_context->udp_proxy_resolver_event = NULL;
560 while (udp_listener_kill_oldest_request(proxy_context) != 0) { }
561 logger_noformat(proxy_context, LOG_INFO, "UDP listener shut down");