dnscrypto-proxy: Update to release 1.3.0
[tomato.git] / release / src / router / dnscrypt / src / proxy / udp_request.c
blobb78111f2fa0efd142ca402814f553609421aa36f
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 assert(event_get_callback_arg(udp_request->sendto_retry_timer)
105 == ctx);
106 free(ctx);
107 event_free(udp_request->sendto_retry_timer);
108 udp_request->sendto_retry_timer = NULL;
110 if (cb) {
111 cb(udp_request);
113 return 0;
116 err = evutil_socket_geterror(udp_request->client_proxy_handle);
117 logger(udp_request->proxy_context, LOG_WARNING,
118 "sendto: [%s]", evutil_socket_error_to_string(err));
119 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(udp_request);
121 #ifdef _WIN32
122 retriable = (err == WSAENOBUFS ||
123 err == WSAEWOULDBLOCK || err == WSAEINTR);
124 #else
125 retriable = (err == ENOBUFS || err == ENOMEM ||
126 err == EAGAIN || err == EINTR);
127 #endif
128 if (retriable == 0) {
129 udp_request_kill(udp_request);
130 return -1;
132 COMPILER_ASSERT(DNS_QUERY_TIMEOUT < UCHAR_MAX);
133 if (++(udp_request->retries) > DNS_QUERY_TIMEOUT) {
134 udp_request_kill(udp_request);
135 return -1;
137 if (udp_request->sendto_retry_timer != NULL) {
138 ctx_cb = event_get_callback_arg(udp_request->sendto_retry_timer);
139 assert(ctx_cb != NULL);
140 assert(ctx_cb->udp_request == ctx->udp_request);
141 assert(ctx_cb->buffer == ctx->buffer);
142 assert(ctx_cb->cb == ctx->cb);
143 } else {
144 if ((ctx_cb = malloc(sizeof *ctx_cb)) == NULL) {
145 logger_error(udp_request->proxy_context, "malloc");
146 udp_request_kill(udp_request);
147 return -1;
149 if ((udp_request->sendto_retry_timer =
150 evtimer_new(udp_request->proxy_context->event_loop,
151 sendto_with_retry_timer_cb, ctx_cb)) == NULL) {
152 free(ctx_cb);
153 udp_request_kill(udp_request);
154 return -1;
156 assert(ctx_cb ==
157 event_get_callback_arg(udp_request->sendto_retry_timer));
158 *ctx_cb = *ctx;
160 const struct timeval tv = {
161 .tv_sec = (time_t) UDP_DELAY_BETWEEN_RETRIES, .tv_usec = 0
163 evtimer_add(udp_request->sendto_retry_timer, &tv);
164 DNSCRYPT_PROXY_REQUEST_UDP_RETRY_SCHEDULED(udp_request,
165 udp_request->retries);
166 return -1;
169 static void
170 resolver_to_proxy_cb(evutil_socket_t proxy_resolver_handle, short ev_flags,
171 void * const proxy_context_)
173 uint8_t dns_reply[DNS_MAX_PACKET_SIZE_UDP];
174 ProxyContext *proxy_context = proxy_context_;
175 UDPRequest *scanned_udp_request;
176 UDPRequest *udp_request = NULL;
177 struct sockaddr_storage resolver_sockaddr;
178 ev_socklen_t resolver_sockaddr_len = sizeof resolver_sockaddr;
179 ssize_t nread;
180 size_t dns_reply_len = (size_t) 0U;
181 size_t uncurved_len;
183 (void) ev_flags;
184 nread = recvfrom(proxy_resolver_handle,
185 (void *) dns_reply, sizeof dns_reply, 0,
186 (struct sockaddr *) &resolver_sockaddr,
187 &resolver_sockaddr_len);
188 if (nread < (ssize_t) 0) {
189 const int err = evutil_socket_geterror(proxy_resolver_handle);
190 logger(proxy_context, LOG_WARNING,
191 "recvfrom(resolver): [%s]", evutil_socket_error_to_string(err));
192 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(NULL);
193 return;
195 if (evutil_sockaddr_cmp((const struct sockaddr *) &resolver_sockaddr,
196 (const struct sockaddr *)
197 &proxy_context->resolver_sockaddr, 1) != 0) {
198 logger_noformat(proxy_context, LOG_WARNING,
199 "Received a resolver reply from a different resolver");
200 return;
202 TAILQ_FOREACH(scanned_udp_request,
203 &proxy_context->udp_request_queue, queue) {
204 if (dnscrypt_cmp_client_nonce(scanned_udp_request->client_nonce,
205 dns_reply, (size_t) nread) == 0) {
206 udp_request = scanned_udp_request;
207 break;
210 if (udp_request == NULL) {
211 logger(proxy_context, LOG_DEBUG,
212 "Received a reply that doesn't match any active query");
213 return;
215 if (nread < (ssize_t) (DNS_HEADER_SIZE + dnscrypt_response_header_size()) ||
216 nread > (ssize_t) sizeof dns_reply) {
217 logger_noformat(proxy_context, LOG_WARNING, "Short reply received");
218 udp_request_kill(udp_request);
219 return;
221 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_REPLIED(udp_request);
222 dns_reply_len = (size_t) nread;
223 assert(dns_reply_len <= sizeof dns_reply);
225 uncurved_len = dns_reply_len;
226 DNSCRYPT_PROXY_REQUEST_UNCURVE_START(udp_request, uncurved_len);
227 if (dnscrypt_client_uncurve
228 (&udp_request->proxy_context->dnscrypt_client,
229 udp_request->client_nonce, dns_reply, &uncurved_len) != 0) {
230 DNSCRYPT_PROXY_REQUEST_UNCURVE_ERROR(udp_request);
231 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_GOT_INVALID_REPLY(udp_request);
232 logger_noformat(udp_request->proxy_context, LOG_WARNING,
233 "Received a suspicious reply from the resolver");
234 udp_request_kill(udp_request);
235 return;
237 DNSCRYPT_PROXY_REQUEST_UNCURVE_DONE(udp_request, uncurved_len);
238 memset(udp_request->client_nonce, 0, sizeof udp_request->client_nonce);
239 assert(uncurved_len <= dns_reply_len);
240 dns_reply_len = uncurved_len;
241 #ifdef PLUGINS
242 const size_t max_reply_size_for_filter = sizeof dns_reply;
243 DCPluginDNSPacket dcp_packet = {
244 .client_sockaddr = &udp_request->client_sockaddr,
245 .dns_packet = dns_reply,
246 .dns_packet_len_p = &dns_reply_len,
247 .client_sockaddr_len_s = (size_t) udp_request->client_sockaddr_len,
248 .dns_packet_max_len = max_reply_size_for_filter
250 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_START(udp_request, dns_reply_len,
251 max_reply_size_for_filter);
252 assert(proxy_context->app_context->dcps_context != NULL);
253 const DCPluginSyncFilterResult res =
254 plugin_support_context_apply_sync_post_filters
255 (proxy_context->app_context->dcps_context, &dcp_packet);
256 assert(dns_reply_len > (size_t) 0U &&
257 dns_reply_len <= sizeof dns_reply &&
258 dns_reply_len <= max_reply_size_for_filter);
259 if (res != DCP_SYNC_FILTER_RESULT_OK) {
260 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_ERROR(udp_request, res);
261 udp_request_kill(udp_request);
262 return;
264 DNSCRYPT_PROXY_REQUEST_PLUGINS_POST_DONE(udp_request, dns_reply_len,
265 max_reply_size_for_filter);
266 #endif
267 sendto_with_retry(& (SendtoWithRetryCtx) {
268 .udp_request = udp_request,
269 .handle = udp_request->client_proxy_handle,
270 .buffer = dns_reply,
271 .length = dns_reply_len,
272 .flags = 0,
273 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
274 .dest_len = udp_request->client_sockaddr_len,
275 .cb = udp_request_kill
279 static void
280 proxy_client_send_truncated(UDPRequest * const udp_request,
281 uint8_t dns_reply[DNS_MAX_PACKET_SIZE_UDP],
282 size_t dns_reply_len)
284 DNSCRYPT_PROXY_REQUEST_UDP_TRUNCATED(udp_request);
286 assert(dns_reply_len > DNS_OFFSET_FLAGS2);
287 dns_reply[DNS_OFFSET_FLAGS] |= DNS_FLAGS_TC | DNS_FLAGS_QR;
288 dns_reply[DNS_OFFSET_FLAGS2] |= DNS_FLAGS2_RA;
289 sendto_with_retry(& (SendtoWithRetryCtx) {
290 .udp_request = udp_request,
291 .handle = udp_request->client_proxy_handle,
292 .buffer = dns_reply,
293 .length = dns_reply_len,
294 .flags = 0,
295 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
296 .dest_len = udp_request->client_sockaddr_len,
297 .cb = udp_request_kill
301 static void
302 timeout_timer_cb(evutil_socket_t timeout_timer_handle, short ev_flags,
303 void * const udp_request_)
305 UDPRequest * const udp_request = udp_request_;
307 (void) ev_flags;
308 (void) timeout_timer_handle;
309 DNSCRYPT_PROXY_REQUEST_UDP_TIMEOUT(udp_request);
310 logger_noformat(udp_request->proxy_context, LOG_DEBUG,
311 "resolver timeout (UDP)");
312 udp_request_kill(udp_request);
315 #ifndef SO_RCVBUFFORCE
316 # define SO_RCVBUFFORCE SO_RCVBUF
317 #endif
318 #ifndef SO_SNDBUFFORCE
319 # define SO_SNDBUFFORCE SO_SNDBUF
320 #endif
322 static void
323 udp_tune(evutil_socket_t const handle)
325 if (handle == -1) {
326 return;
328 setsockopt(handle, SOL_SOCKET, SO_RCVBUFFORCE,
329 (void *) (int []) { UDP_BUFFER_SIZE }, sizeof (int));
330 setsockopt(handle, SOL_SOCKET, SO_SNDBUFFORCE,
331 (void *) (int []) { UDP_BUFFER_SIZE }, sizeof (int));
332 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
333 setsockopt(handle, IPPROTO_IP, IP_MTU_DISCOVER,
334 (void *) (int []) { IP_PMTUDISC_DONT }, sizeof (int));
335 #elif defined(IP_DONTFRAG)
336 setsockopt(handle, IPPROTO_IP, IP_DONTFRAG,
337 (void *) (int []) { 0 }, sizeof (int));
338 #endif
341 static void
342 client_to_proxy_cb_sendto_cb(UDPRequest * const udp_request)
344 (void) udp_request;
345 DNSCRYPT_PROXY_REQUEST_UDP_PROXY_RESOLVER_START(udp_request);
348 #ifdef PLUGINS
349 static void
350 proxy_to_client_direct(UDPRequest * const udp_request,
351 const uint8_t * const dns_reply,
352 const size_t dns_reply_len)
354 sendto_with_retry(& (SendtoWithRetryCtx) {
355 .udp_request = udp_request,
356 .handle = udp_request->client_proxy_handle,
357 .buffer = dns_reply,
358 .length = dns_reply_len,
359 .flags = 0,
360 .dest_addr = (struct sockaddr *) &udp_request->client_sockaddr,
361 .dest_len = udp_request->client_sockaddr_len,
362 .cb = udp_request_kill
365 #endif
367 static void
368 client_to_proxy_cb(evutil_socket_t client_proxy_handle, short ev_flags,
369 void * const proxy_context_)
371 uint8_t dns_query[DNS_MAX_PACKET_SIZE_UDP];
372 ProxyContext *proxy_context = proxy_context_;
373 UDPRequest *udp_request;
374 ssize_t curve_ret;
375 ssize_t nread;
376 size_t dns_query_len = (size_t) 0U;
377 size_t max_query_size;
378 size_t request_edns_payload_size;
380 (void) ev_flags;
381 assert(client_proxy_handle == proxy_context->udp_listener_handle);
382 if ((udp_request = calloc((size_t) 1U, sizeof *udp_request)) == NULL) {
383 return;
385 udp_request->proxy_context = proxy_context;
386 udp_request->sendto_retry_timer = NULL;
387 udp_request->timeout_timer = NULL;
388 udp_request->client_proxy_handle = client_proxy_handle;
389 udp_request->client_sockaddr_len = sizeof udp_request->client_sockaddr;
390 nread = recvfrom(client_proxy_handle,
391 (void *) dns_query, sizeof dns_query, 0,
392 (struct sockaddr *) &udp_request->client_sockaddr,
393 &udp_request->client_sockaddr_len);
394 if (nread < (ssize_t) 0) {
395 const int err = evutil_socket_geterror(client_proxy_handle);
396 logger(proxy_context, LOG_WARNING,
397 "recvfrom(client): [%s]", evutil_socket_error_to_string(err));
398 DNSCRYPT_PROXY_REQUEST_UDP_NETWORK_ERROR(udp_request);
399 udp_request_kill(udp_request);
400 return;
402 if (nread < (ssize_t) DNS_HEADER_SIZE ||
403 (size_t) nread > sizeof dns_query) {
404 logger_noformat(proxy_context, LOG_WARNING, "Short query received");
405 free(udp_request);
406 return;
408 if (proxy_context->connections_count >=
409 proxy_context->connections_count_max) {
410 DNSCRYPT_PROXY_REQUEST_UDP_OVERLOADED();
411 if (udp_listener_kill_oldest_request(proxy_context) != 0) {
412 tcp_listener_kill_oldest_request(proxy_context);
415 proxy_context->connections_count++;
416 assert(proxy_context->connections_count
417 <= proxy_context->connections_count_max);
418 DNSCRYPT_PROXY_STATUS_REQUESTS_ACTIVE(proxy_context->connections_count,
419 proxy_context->connections_count_max);
420 DNSCRYPT_PROXY_REQUEST_UDP_START(udp_request);
421 TAILQ_INSERT_TAIL(&proxy_context->udp_request_queue,
422 udp_request, queue);
423 memset(&udp_request->status, 0, sizeof udp_request->status);
424 udp_request->status.is_in_queue = 1;
426 dns_query_len = (size_t) nread;
427 assert(dns_query_len <= sizeof dns_query);
429 edns_add_section(proxy_context, dns_query, &dns_query_len,
430 sizeof dns_query, &request_edns_payload_size);
432 if (request_edns_payload_size < DNS_MAX_PACKET_SIZE_UDP_SEND) {
433 max_query_size = DNS_MAX_PACKET_SIZE_UDP_SEND;
434 } else {
435 max_query_size = request_edns_payload_size;
437 if (max_query_size > sizeof dns_query) {
438 max_query_size = sizeof dns_query;
440 assert(max_query_size <= sizeof dns_query);
441 if (udp_request->proxy_context->tcp_only != 0) {
442 proxy_client_send_truncated(udp_request, dns_query, dns_query_len);
443 return;
445 #ifdef PLUGINS
446 size_t max_query_size_for_filter = dns_query_len;
447 if (max_query_size > DNSCRYPT_MAX_PADDING + dnscrypt_query_header_size()) {
448 max_query_size_for_filter = max_query_size -
449 (DNSCRYPT_MAX_PADDING + dnscrypt_query_header_size());
451 DCPluginDNSPacket dcp_packet = {
452 .client_sockaddr = &udp_request->client_sockaddr,
453 .dns_packet = dns_query,
454 .dns_packet_len_p = &dns_query_len,
455 .client_sockaddr_len_s = (size_t) udp_request->client_sockaddr_len,
456 .dns_packet_max_len = max_query_size_for_filter
458 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_START(udp_request, dns_query_len,
459 max_query_size_for_filter);
460 assert(proxy_context->app_context->dcps_context != NULL);
461 const DCPluginSyncFilterResult res =
462 plugin_support_context_apply_sync_pre_filters
463 (proxy_context->app_context->dcps_context, &dcp_packet);
464 assert(dns_query_len > (size_t) 0U && dns_query_len <= max_query_size &&
465 dns_query_len <= max_query_size_for_filter);
466 switch (res) {
467 case DCP_SYNC_FILTER_RESULT_OK:
468 break;
469 case DCP_SYNC_FILTER_RESULT_DIRECT:
470 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_DONE(udp_request, dns_query_len,
471 max_query_size_for_filter);
472 proxy_to_client_direct(udp_request, dns_query, dns_query_len);
473 return;
474 default:
475 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_ERROR(udp_request, res);
476 udp_request_kill(udp_request);
477 return;
479 DNSCRYPT_PROXY_REQUEST_PLUGINS_PRE_DONE(udp_request, dns_query_len,
480 max_query_size_for_filter);
481 #endif
482 assert(SIZE_MAX - DNSCRYPT_MAX_PADDING - dnscrypt_query_header_size()
483 > dns_query_len);
484 size_t max_len = dns_query_len + DNSCRYPT_MAX_PADDING +
485 dnscrypt_query_header_size();
486 if (max_len > max_query_size) {
487 max_len = max_query_size;
489 if (dns_query_len + dnscrypt_query_header_size() > max_len) {
490 proxy_client_send_truncated(udp_request, dns_query, dns_query_len);
491 return;
493 DNSCRYPT_PROXY_REQUEST_CURVE_START(udp_request, dns_query_len);
494 curve_ret =
495 dnscrypt_client_curve(&udp_request->proxy_context->dnscrypt_client,
496 udp_request->client_nonce, dns_query,
497 dns_query_len, max_len);
498 if (curve_ret <= (ssize_t) 0) {
499 DNSCRYPT_PROXY_REQUEST_CURVE_ERROR(udp_request);
500 return;
502 dns_query_len = (size_t) curve_ret;
503 assert(dns_query_len >= dnscrypt_query_header_size());
504 DNSCRYPT_PROXY_REQUEST_CURVE_DONE(udp_request, dns_query_len);
505 assert(dns_query_len <= sizeof dns_query);
507 udp_request->timeout_timer =
508 evtimer_new(udp_request->proxy_context->event_loop,
509 timeout_timer_cb, udp_request);
510 if (udp_request->timeout_timer != NULL) {
511 const struct timeval tv = {
512 .tv_sec = (time_t) DNS_QUERY_TIMEOUT, .tv_usec = 0
514 evtimer_add(udp_request->timeout_timer, &tv);
516 sendto_with_retry(& (SendtoWithRetryCtx) {
517 .udp_request = udp_request,
518 .handle = proxy_context->udp_proxy_resolver_handle,
519 .buffer = dns_query,
520 .length = dns_query_len,
521 .flags = 0,
522 .dest_addr = (struct sockaddr *) &proxy_context->resolver_sockaddr,
523 .dest_len = proxy_context->resolver_sockaddr_len,
524 .cb = client_to_proxy_cb_sendto_cb
529 udp_listener_kill_oldest_request(ProxyContext * const proxy_context)
531 if (TAILQ_EMPTY(&proxy_context->udp_request_queue)) {
532 return -1;
534 udp_request_kill(TAILQ_FIRST(&proxy_context->udp_request_queue));
536 return 0;
540 udp_listener_bind(ProxyContext * const proxy_context)
542 assert(proxy_context->udp_listener_handle == -1);
543 if ((proxy_context->udp_listener_handle = socket
544 (proxy_context->local_sockaddr.ss_family,
545 SOCK_DGRAM, IPPROTO_UDP)) == -1) {
546 logger(NULL, LOG_ERR, "Unable to create a socket (UDP)");
547 return -1;
549 evutil_make_socket_closeonexec(proxy_context->udp_listener_handle);
550 evutil_make_socket_nonblocking(proxy_context->udp_listener_handle);
551 if (bind(proxy_context->udp_listener_handle,
552 (struct sockaddr *) &proxy_context->local_sockaddr,
553 proxy_context->local_sockaddr_len) != 0) {
554 logger(NULL, LOG_ERR, "Unable to bind (UDP) [%s]",
555 evutil_socket_error_to_string
556 (evutil_socket_geterror(proxy_context->udp_listener_handle)));
557 evutil_closesocket(proxy_context->udp_listener_handle);
558 proxy_context->udp_listener_handle = -1;
559 return -1;
561 udp_tune(proxy_context->udp_listener_handle);
563 if ((proxy_context->udp_proxy_resolver_handle = socket
564 (proxy_context->resolver_sockaddr.ss_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
565 logger_noformat(proxy_context, LOG_ERR,
566 "Unable to create a socket to the resolver");
567 evutil_closesocket(proxy_context->udp_listener_handle);
568 proxy_context->udp_listener_handle = -1;
569 return -1;
571 evutil_make_socket_closeonexec(proxy_context->udp_proxy_resolver_handle);
572 evutil_make_socket_nonblocking(proxy_context->udp_proxy_resolver_handle);
573 udp_tune(proxy_context->udp_proxy_resolver_handle);
575 TAILQ_INIT(&proxy_context->udp_request_queue);
577 return 0;
581 udp_listener_start(ProxyContext * const proxy_context)
583 assert(proxy_context->udp_listener_handle != -1);
584 if ((proxy_context->udp_listener_event =
585 event_new(proxy_context->event_loop,
586 proxy_context->udp_listener_handle, EV_READ | EV_PERSIST,
587 client_to_proxy_cb, proxy_context)) == NULL) {
588 return -1;
590 if (event_add(proxy_context->udp_listener_event, NULL) != 0) {
591 udp_listener_stop(proxy_context);
592 return -1;
595 assert(proxy_context->udp_proxy_resolver_handle != -1);
596 if ((proxy_context->udp_proxy_resolver_event =
597 event_new(proxy_context->event_loop,
598 proxy_context->udp_proxy_resolver_handle,
599 EV_READ | EV_PERSIST,
600 resolver_to_proxy_cb, proxy_context)) == NULL) {
601 udp_listener_stop(proxy_context);
602 return -1;
604 if (event_add(proxy_context->udp_proxy_resolver_event, NULL) != 0) {
605 udp_listener_stop(proxy_context);
606 return -1;
608 return 0;
611 void
612 udp_listener_stop(ProxyContext * const proxy_context)
614 event_free(proxy_context->udp_proxy_resolver_event);
615 proxy_context->udp_proxy_resolver_event = NULL;
616 while (udp_listener_kill_oldest_request(proxy_context) != 0) { }
617 logger_noformat(proxy_context, LOG_INFO, "UDP listener shut down");