dnscrypt-proxy 1.4.0
[tomato.git] / release / src / router / dnscrypt / src / proxy / udp_request.c
bloba26ef4fde29c9cdc66011d345c54136508cd8bc3
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->sendto_retry_timer != NULL) {
42 free(event_get_callback_arg(udp_request->sendto_retry_timer));
43 event_free(udp_request->sendto_retry_timer);
44 udp_request->sendto_retry_timer = NULL;
46 if (udp_request->timeout_timer != NULL) {
47 event_free(udp_request->timeout_timer);
48 udp_request->timeout_timer = NULL;
50 DNSCRYPT_PROXY_REQUEST_UDP_DONE(udp_request);
51 proxy_context = udp_request->proxy_context;
52 if (udp_request->status.is_in_queue != 0) {
53 assert(! TAILQ_EMPTY(&proxy_context->udp_request_queue));
54 TAILQ_REMOVE(&proxy_context->udp_request_queue, udp_request, queue);
55 assert(proxy_context->connections_count > 0U);
56 proxy_context->connections_count--;
57 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
58 proxy_context->connections_count_max);
60 udp_request->proxy_context = NULL;
61 free(udp_request);
64 static void
65 udp_request_kill(UDPRequest * const udp_request)
67 if (udp_request == NULL || udp_request->status.is_dying) {
68 return;
70 udp_request->status.is_dying = 1;
71 udp_request_free(udp_request);
74 static int sendto_with_retry(SendtoWithRetryCtx * const ctx);
76 static void
77 sendto_with_retry_timer_cb(evutil_socket_t retry_timer_handle, short ev_flags,
78 void * const ctx_)
80 SendtoWithRetryCtx * const ctx = ctx_;
82 (void) ev_flags;
83 assert(retry_timer_handle ==
84 event_get_fd(ctx->udp_request->sendto_retry_timer));
86 DNSCRYPT_PROXY_REQUEST_UDP_RETRY(ctx->udp_request,
87 ctx->udp_request->retries);
88 sendto_with_retry(ctx);
91 static int
92 sendto_with_retry(SendtoWithRetryCtx * const ctx)
94 void (*cb)(UDPRequest *udp_request);
95 SendtoWithRetryCtx *ctx_cb;
96 UDPRequest *udp_request = ctx->udp_request;
97 int err;
98 _Bool retriable;
100 if (sendto(ctx->handle, ctx->buffer, ctx->length, ctx->flags,
101 ctx->dest_addr, ctx->dest_len) == (ssize_t) ctx->length) {
102 cb = ctx->cb;
103 if (udp_request->sendto_retry_timer != NULL) {
104 ctx_cb = event_get_callback_arg(udp_request->sendto_retry_timer);
105 assert(ctx_cb != NULL);
106 assert(ctx_cb->udp_request == ctx->udp_request);
107 assert(ctx_cb->buffer == ctx->buffer);
108 free(ctx_cb);
109 event_free(udp_request->sendto_retry_timer);
110 udp_request->sendto_retry_timer = NULL;
112 if (cb) {
113 cb(udp_request);
115 return 0;
118 err = evutil_socket_geterror(udp_request->client_proxy_handle);
119 logger(udp_request->proxy_context, LOG_WARNING,
120 "sendto: [%s]", evutil_socket_error_to_string(err));
121 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(udp_request);
123 #ifdef _WIN32
124 retriable = (err == WSAENOBUFS ||
125 err == WSAEWOULDBLOCK || err == WSAEINTR);
126 #else
127 retriable = (err == ENOBUFS || err == ENOMEM ||
128 err == EAGAIN || err == EINTR);
129 #endif
130 if (retriable == 0) {
131 udp_request_kill(udp_request);
132 return -1;
134 COMPILER_ASSERT(DNS_QUERY_TIMEOUT < UCHAR_MAX);
135 if (++(udp_request->retries) > DNS_QUERY_TIMEOUT) {
136 udp_request_kill(udp_request);
137 return -1;
139 if (udp_request->sendto_retry_timer != NULL) {
140 ctx_cb = event_get_callback_arg(udp_request->sendto_retry_timer);
141 assert(ctx_cb != NULL);
142 assert(ctx_cb->udp_request == ctx->udp_request);
143 assert(ctx_cb->buffer == ctx->buffer);
144 } else {
145 if ((ctx_cb = malloc(sizeof *ctx_cb)) == NULL) {
146 logger_error(udp_request->proxy_context, "malloc");
147 udp_request_kill(udp_request);
148 return -1;
150 assert(ctx_cb ==
151 event_get_callback_arg(udp_request->sendto_retry_timer));
152 *ctx_cb = *ctx;
153 if ((udp_request->sendto_retry_timer =
154 evtimer_new(udp_request->proxy_context->event_loop,
155 sendto_with_retry_timer_cb, ctx_cb)) == NULL) {
156 free(ctx_cb);
157 udp_request_kill(udp_request);
158 return -1;
161 const struct timeval tv = {
162 .tv_sec = (time_t) UDP_DELAY_BETWEEN_RETRIES, .tv_usec = 0
164 evtimer_add(udp_request->sendto_retry_timer, &tv);
165 DNSCRYPT_PROXY_REQUEST_UDP_RETRY_SCHEDULED(udp_request,
166 udp_request->retries);
167 return -1;
170 static void
171 resolver_to_proxy_cb(evutil_socket_t proxy_resolver_handle, short ev_flags,
172 void * const proxy_context_)
174 uint8_t dns_reply[DNS_MAX_PACKET_SIZE_UDP];
175 ProxyContext *proxy_context = proxy_context_;
176 UDPRequest *scanned_udp_request;
177 UDPRequest *udp_request = NULL;
178 struct sockaddr_storage resolver_sockaddr;
179 ev_socklen_t resolver_sockaddr_len = sizeof resolver_sockaddr;
180 ssize_t nread;
181 size_t dns_reply_len = (size_t) 0U;
182 size_t uncurved_len;
184 (void) ev_flags;
185 nread = recvfrom(proxy_resolver_handle,
186 (void *) dns_reply, sizeof dns_reply, 0,
187 (struct sockaddr *) &resolver_sockaddr,
188 &resolver_sockaddr_len);
189 if (nread < (ssize_t) 0) {
190 const int err = evutil_socket_geterror(proxy_resolver_handle);
191 logger(proxy_context, LOG_WARNING,
192 "recvfrom(resolver): [%s]", evutil_socket_error_to_string(err));
193 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(NULL);
194 return;
196 if (evutil_sockaddr_cmp((const struct sockaddr *) &resolver_sockaddr,
197 (const struct sockaddr *)
198 &proxy_context->resolver_sockaddr, 1) != 0) {
199 logger_noformat(proxy_context, LOG_DEBUG,
200 "Received a resolver reply from a different resolver");
201 return;
203 TAILQ_FOREACH(scanned_udp_request,
204 &proxy_context->udp_request_queue, queue) {
205 if (dnscrypt_cmp_client_nonce(scanned_udp_request->client_nonce,
206 dns_reply, (size_t) nread) == 0) {
207 udp_request = scanned_udp_request;
208 break;
211 if (udp_request == NULL) {
212 logger(proxy_context, LOG_DEBUG,
213 "Received a reply that doesn't match any active query");
214 return;
216 if (nread < (ssize_t) (DNS_HEADER_SIZE + dnscrypt_response_header_size()) ||
217 nread > (ssize_t) sizeof dns_reply) {
218 logger_noformat(proxy_context, LOG_WARNING, "Short reply received");
219 udp_request_kill(udp_request);
220 return;
222 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_REPLIED(udp_request);
223 dns_reply_len = (size_t) nread;
224 assert(dns_reply_len <= sizeof dns_reply);
226 uncurved_len = dns_reply_len;
227 DNSCRYPT_PROXY_REQUEST_UNCURVE_START(udp_request, uncurved_len);
228 if (dnscrypt_client_uncurve
229 (&udp_request->proxy_context->dnscrypt_client,
230 udp_request->client_nonce, dns_reply, &uncurved_len) != 0) {
231 DNSCRYPT_PROXY_REQUEST_UNCURVE_ERROR(udp_request);
232 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_GOT_INVALID_REPLY(udp_request);
233 logger_noformat(udp_request->proxy_context, LOG_WARNING,
234 "Received a suspicious reply from the resolver");
235 udp_request_kill(udp_request);
236 return;
238 DNSCRYPT_PROXY_REQUEST_UNCURVE_DONE(udp_request, uncurved_len);
239 memset(udp_request->client_nonce, 0, sizeof udp_request->client_nonce);
240 assert(uncurved_len <= dns_reply_len);
241 dns_reply_len = uncurved_len;
243 assert(dns_reply_len >= DNS_HEADER_SIZE);
244 COMPILER_ASSERT(DNS_OFFSET_FLAGS < DNS_HEADER_SIZE);
245 if ((dns_reply[DNS_OFFSET_FLAGS] & DNS_FLAGS_TC) != 0) {
246 if (proxy_context->udp_current_max_size <
247 proxy_context->udp_max_size) {
248 COMPILER_ASSERT(DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND >=
249 DNSCRYPT_BLOCK_SIZE);
250 if (proxy_context->udp_max_size -
251 proxy_context->udp_current_max_size > DNSCRYPT_BLOCK_SIZE) {
252 proxy_context->udp_current_max_size += DNSCRYPT_BLOCK_SIZE;
253 } else {
254 proxy_context->udp_current_max_size =
255 proxy_context->udp_max_size;
260 #ifdef PLUGINS
261 const size_t max_reply_size_for_filter = sizeof dns_reply;
262 DCPluginDNSPacket dcp_packet = {
263 .client_sockaddr = &udp_request->client_sockaddr,
264 .dns_packet = dns_reply,
265 .dns_packet_len_p = &dns_reply_len,
266 .client_sockaddr_len_s = (size_t) udp_request->client_sockaddr_len,
267 .dns_packet_max_len = max_reply_size_for_filter
269 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_START(udp_request, dns_reply_len,
270 max_reply_size_for_filter);
271 assert(proxy_context->app_context->dcps_context != NULL);
272 const DCPluginSyncFilterResult res =
273 plugin_support_context_apply_sync_post_filters
274 (proxy_context->app_context->dcps_context, &dcp_packet);
275 assert(dns_reply_len > (size_t) 0U &&
276 dns_reply_len <= sizeof dns_reply &&
277 dns_reply_len <= max_reply_size_for_filter);
278 if (res != DCP_SYNC_FILTER_RESULT_OK) {
279 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_ERROR(udp_request, res);
280 udp_request_kill(udp_request);
281 return;
283 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_DONE(udp_request, dns_reply_len,
284 max_reply_size_for_filter);
285 #endif
286 sendto_with_retry(& (SendtoWithRetryCtx) {
287 .udp_request = udp_request,
288 .handle = udp_request->client_proxy_handle,
289 .buffer = dns_reply,
290 .length = dns_reply_len,
291 .flags = 0,
292 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
293 .dest_len = udp_request->client_sockaddr_len,
294 .cb = udp_request_kill
298 static void
299 proxy_client_send_truncated(UDPRequest * const udp_request,
300 uint8_t dns_reply[DNS_MAX_PACKET_SIZE_UDP],
301 size_t dns_reply_len)
303 DNSCRYPT_PROXY_REQUEST_UDP_TRUNCATED(udp_request);
305 assert(dns_reply_len > DNS_OFFSET_FLAGS2);
306 dns_reply[DNS_OFFSET_FLAGS] |= DNS_FLAGS_TC | DNS_FLAGS_QR;
307 dns_reply[DNS_OFFSET_FLAGS2] |= DNS_FLAGS2_RA;
308 sendto_with_retry(& (SendtoWithRetryCtx) {
309 .udp_request = udp_request,
310 .handle = udp_request->client_proxy_handle,
311 .buffer = dns_reply,
312 .length = dns_reply_len,
313 .flags = 0,
314 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
315 .dest_len = udp_request->client_sockaddr_len,
316 .cb = udp_request_kill
320 static void
321 timeout_timer_cb(evutil_socket_t timeout_timer_handle, short ev_flags,
322 void * const udp_request_)
324 UDPRequest * const udp_request = udp_request_;
326 (void) ev_flags;
327 (void) timeout_timer_handle;
328 DNSCRYPT_PROXY_REQUEST_UDP_TIMEOUT(udp_request);
329 logger_noformat(udp_request->proxy_context, LOG_DEBUG,
330 "resolver timeout (UDP)");
331 udp_request_kill(udp_request);
334 #ifndef SO_RCVBUFFORCE
335 # define SO_RCVBUFFORCE SO_RCVBUF
336 #endif
337 #ifndef SO_SNDBUFFORCE
338 # define SO_SNDBUFFORCE SO_SNDBUF
339 #endif
341 static void
342 udp_tune(evutil_socket_t const handle)
344 if (handle == -1) {
345 return;
347 setsockopt(handle, SOL_SOCKET, SO_RCVBUFFORCE,
348 (void *) (int []) { UDP_BUFFER_SIZE }, sizeof (int));
349 setsockopt(handle, SOL_SOCKET, SO_SNDBUFFORCE,
350 (void *) (int []) { UDP_BUFFER_SIZE }, sizeof (int));
351 #if defined(IP_PMTUDISC_OMIT)
352 setsockopt(handle, IPPROTO_IP, IP_MTU_DISCOVER,
353 (void *) (int []) { IP_PMTUDISC_OMIT }, sizeof (int));
354 #elif defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
355 setsockopt(handle, IPPROTO_IP, IP_MTU_DISCOVER,
356 (void *) (int []) { IP_PMTUDISC_DONT }, sizeof (int));
357 #elif defined(IP_DONTFRAG)
358 setsockopt(handle, IPPROTO_IP, IP_DONTFRAG,
359 (void *) (int []) { 0 }, sizeof (int));
360 #endif
363 static void
364 client_to_proxy_cb_sendto_cb(UDPRequest * const udp_request)
366 (void) udp_request;
367 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_START(udp_request);
370 #ifdef PLUGINS
371 static void
372 proxy_to_client_direct(UDPRequest * const udp_request,
373 const uint8_t * const dns_reply,
374 const size_t dns_reply_len)
376 sendto_with_retry(& (SendtoWithRetryCtx) {
377 .udp_request = udp_request,
378 .handle = udp_request->client_proxy_handle,
379 .buffer = dns_reply,
380 .length = dns_reply_len,
381 .flags = 0,
382 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
383 .dest_len = udp_request->client_sockaddr_len,
384 .cb = udp_request_kill
387 #endif
389 static void
390 client_to_proxy_cb(evutil_socket_t client_proxy_handle, short ev_flags,
391 void * const proxy_context_)
393 uint8_t dns_query[DNS_MAX_PACKET_SIZE_UDP];
394 ProxyContext *proxy_context = proxy_context_;
395 UDPRequest *udp_request;
396 ssize_t curve_ret;
397 ssize_t nread;
398 size_t dns_query_len = (size_t) 0U;
399 size_t max_query_size;
400 size_t request_edns_payload_size;
402 (void) ev_flags;
403 assert(client_proxy_handle == proxy_context->udp_listener_handle);
404 if ((udp_request = calloc((size_t) 1U, sizeof *udp_request)) == NULL) {
405 return;
407 udp_request->proxy_context = proxy_context;
408 udp_request->sendto_retry_timer = NULL;
409 udp_request->timeout_timer = NULL;
410 udp_request->client_proxy_handle = client_proxy_handle;
411 udp_request->client_sockaddr_len = sizeof udp_request->client_sockaddr;
412 nread = recvfrom(client_proxy_handle,
413 (void *) dns_query, sizeof dns_query, 0,
414 (struct sockaddr *) &udp_request->client_sockaddr,
415 &udp_request->client_sockaddr_len);
416 if (nread < (ssize_t) 0) {
417 const int err = evutil_socket_geterror(client_proxy_handle);
418 logger(proxy_context, LOG_WARNING,
419 "recvfrom(client): [%s]", evutil_socket_error_to_string(err));
420 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(udp_request);
421 udp_request_kill(udp_request);
422 return;
424 if (nread < (ssize_t) DNS_HEADER_SIZE ||
425 (size_t) nread > sizeof dns_query) {
426 logger_noformat(proxy_context, LOG_WARNING, "Short query received");
427 free(udp_request);
428 return;
430 if (proxy_context->connections_count >=
431 proxy_context->connections_count_max) {
432 DNSCRYPT_PROXY_REQUEST_UDP_OVERLOADED();
433 if (udp_listener_kill_oldest_request(proxy_context) != 0) {
434 tcp_listener_kill_oldest_request(proxy_context);
437 proxy_context->connections_count++;
438 assert(proxy_context->connections_count
439 <= proxy_context->connections_count_max);
440 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
441 proxy_context->connections_count_max);
442 DNSCRYPT_PROXY_REQUEST_UDP_START(udp_request);
443 TAILQ_INSERT_TAIL(&proxy_context->udp_request_queue,
444 udp_request, queue);
445 memset(&udp_request->status, 0, sizeof udp_request->status);
446 udp_request->status.is_in_queue = 1;
448 dns_query_len = (size_t) nread;
449 assert(dns_query_len <= sizeof dns_query);
451 edns_add_section(proxy_context, dns_query, &dns_query_len,
452 sizeof dns_query, &request_edns_payload_size);
454 if (request_edns_payload_size < DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND) {
455 max_query_size = DNS_MAX_PACKET_SIZE_UDP_NO_EDNS_SEND;
456 } else {
457 max_query_size = request_edns_payload_size;
459 if (max_query_size > sizeof dns_query) {
460 max_query_size = sizeof dns_query;
462 assert(max_query_size <= sizeof dns_query);
463 if (udp_request->proxy_context->tcp_only != 0) {
464 proxy_client_send_truncated(udp_request, dns_query, dns_query_len);
465 return;
467 #ifdef PLUGINS
468 size_t max_query_size_for_filter = dns_query_len;
469 if (max_query_size > DNSCRYPT_MAX_PADDING + dnscrypt_query_header_size()) {
470 max_query_size_for_filter = max_query_size -
471 (DNSCRYPT_MAX_PADDING + dnscrypt_query_header_size());
473 DCPluginDNSPacket dcp_packet = {
474 .client_sockaddr = &udp_request->client_sockaddr,
475 .dns_packet = dns_query,
476 .dns_packet_len_p = &dns_query_len,
477 .client_sockaddr_len_s = (size_t) udp_request->client_sockaddr_len,
478 .dns_packet_max_len = max_query_size_for_filter
480 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_START(udp_request, dns_query_len,
481 max_query_size_for_filter);
482 assert(proxy_context->app_context->dcps_context != NULL);
483 const DCPluginSyncFilterResult res =
484 plugin_support_context_apply_sync_pre_filters
485 (proxy_context->app_context->dcps_context, &dcp_packet);
486 assert(dns_query_len > (size_t) 0U && dns_query_len <= max_query_size &&
487 dns_query_len <= max_query_size_for_filter);
488 switch (res) {
489 case DCP_SYNC_FILTER_RESULT_OK:
490 break;
491 case DCP_SYNC_FILTER_RESULT_DIRECT:
492 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_DONE(udp_request, dns_query_len,
493 max_query_size_for_filter);
494 proxy_to_client_direct(udp_request, dns_query, dns_query_len);
495 return;
496 default:
497 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_ERROR(udp_request, res);
498 udp_request_kill(udp_request);
499 return;
501 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_DONE(udp_request, dns_query_len,
502 max_query_size_for_filter);
503 #endif
504 assert(SIZE_MAX - DNSCRYPT_MAX_PADDING - dnscrypt_query_header_size()
505 > dns_query_len);
507 size_t max_len;
508 max_len = proxy_context->udp_current_max_size;
509 if (max_len > max_query_size) {
510 max_len = max_query_size;
512 if (dns_query_len + dnscrypt_query_header_size() > max_len) {
513 proxy_client_send_truncated(udp_request, dns_query, dns_query_len);
514 return;
516 DNSCRYPT_PROXY_REQUEST_CURVE_START(udp_request, dns_query_len);
517 curve_ret =
518 dnscrypt_client_curve(&udp_request->proxy_context->dnscrypt_client,
519 udp_request->client_nonce, dns_query,
520 dns_query_len, max_len);
521 if (curve_ret <= (ssize_t) 0) {
522 DNSCRYPT_PROXY_REQUEST_CURVE_ERROR(udp_request);
523 return;
525 dns_query_len = (size_t) curve_ret;
526 assert(dns_query_len >= dnscrypt_query_header_size());
527 DNSCRYPT_PROXY_REQUEST_CURVE_DONE(udp_request, dns_query_len);
528 assert(dns_query_len <= sizeof dns_query);
530 udp_request->timeout_timer =
531 evtimer_new(udp_request->proxy_context->event_loop,
532 timeout_timer_cb, udp_request);
533 if (udp_request->timeout_timer != NULL) {
534 const struct timeval tv = {
535 .tv_sec = (time_t) DNS_QUERY_TIMEOUT, .tv_usec = 0
537 evtimer_add(udp_request->timeout_timer, &tv);
539 sendto_with_retry(& (SendtoWithRetryCtx) {
540 .udp_request = udp_request,
541 .handle = proxy_context->udp_proxy_resolver_handle,
542 .buffer = dns_query,
543 .length = dns_query_len,
544 .flags = 0,
545 .dest_addr = (struct sockaddr *) &proxy_context->resolver_sockaddr,
546 .dest_len = proxy_context->resolver_sockaddr_len,
547 .cb = client_to_proxy_cb_sendto_cb
552 udp_listener_kill_oldest_request(ProxyContext * const proxy_context)
554 if (TAILQ_EMPTY(&proxy_context->udp_request_queue)) {
555 return -1;
557 udp_request_kill(TAILQ_FIRST(&proxy_context->udp_request_queue));
559 return 0;
563 udp_listener_bind(ProxyContext * const proxy_context)
565 assert(proxy_context->udp_listener_handle == -1);
566 if ((proxy_context->udp_listener_handle = socket
567 (proxy_context->local_sockaddr.ss_family,
568 SOCK_DGRAM, IPPROTO_UDP)) == -1) {
569 logger(NULL, LOG_ERR, "Unable to create a socket (UDP)");
570 return -1;
572 evutil_make_socket_closeonexec(proxy_context->udp_listener_handle);
573 evutil_make_socket_nonblocking(proxy_context->udp_listener_handle);
574 if (bind(proxy_context->udp_listener_handle,
575 (struct sockaddr *) &proxy_context->local_sockaddr,
576 proxy_context->local_sockaddr_len) != 0) {
577 logger(NULL, LOG_ERR, "Unable to bind (UDP) [%s]",
578 evutil_socket_error_to_string
579 (evutil_socket_geterror(proxy_context->udp_listener_handle)));
580 evutil_closesocket(proxy_context->udp_listener_handle);
581 proxy_context->udp_listener_handle = -1;
582 return -1;
584 udp_tune(proxy_context->udp_listener_handle);
586 if ((proxy_context->udp_proxy_resolver_handle = socket
587 (proxy_context->resolver_sockaddr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
588 logger_noformat(proxy_context, LOG_ERR,
589 "Unable to create a socket to the resolver");
590 evutil_closesocket(proxy_context->udp_listener_handle);
591 proxy_context->udp_listener_handle = -1;
592 return -1;
594 evutil_make_socket_closeonexec(proxy_context->udp_proxy_resolver_handle);
595 evutil_make_socket_nonblocking(proxy_context->udp_proxy_resolver_handle);
596 udp_tune(proxy_context->udp_proxy_resolver_handle);
598 TAILQ_INIT(&proxy_context->udp_request_queue);
600 return 0;
604 udp_listener_start(ProxyContext * const proxy_context)
606 assert(proxy_context->udp_listener_handle != -1);
607 if ((proxy_context->udp_listener_event =
608 event_new(proxy_context->event_loop,
609 proxy_context->udp_listener_handle, EV_READ | EV_PERSIST,
610 client_to_proxy_cb, proxy_context)) == NULL) {
611 return -1;
613 if (event_add(proxy_context->udp_listener_event, NULL) != 0) {
614 udp_listener_stop(proxy_context);
615 return -1;
618 assert(proxy_context->udp_proxy_resolver_handle != -1);
619 if ((proxy_context->udp_proxy_resolver_event =
620 event_new(proxy_context->event_loop,
621 proxy_context->udp_proxy_resolver_handle,
622 EV_READ | EV_PERSIST,
623 resolver_to_proxy_cb, proxy_context)) == NULL) {
624 udp_listener_stop(proxy_context);
625 return -1;
627 if (event_add(proxy_context->udp_proxy_resolver_event, NULL) != 0) {
628 udp_listener_stop(proxy_context);
629 return -1;
631 return 0;
634 void
635 udp_listener_stop(ProxyContext * const proxy_context)
637 event_free(proxy_context->udp_proxy_resolver_event);
638 proxy_context->udp_proxy_resolver_event = NULL;
639 while (udp_listener_kill_oldest_request(proxy_context) != 0) { }
640 logger_noformat(proxy_context, LOG_INFO, "UDP listener shut down");