VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/pxdns.c@ 49409

Last change on this file since 49409 was 49299, checked in by vboxsync, 11 years ago

On Windows getsockopt() takes char *, not void * - add cast to pacify compiler

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.0 KB
Line 
1/* -*- indent-tabs-mode: nil; -*- */
2
3/*
4 * Copyright (C) 2009-2013 Oracle Corporation
5 *
6 * This file is part of VirtualBox Open Source Edition (OSE), as
7 * available from http://www.virtualbox.org. This file is free software;
8 * you can redistribute it and/or modify it under the terms of the GNU
9 * General Public License (GPL) as published by the Free Software
10 * Foundation, in version 2 as it comes in the "COPYING" file of the
11 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
12 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
13 */
14
15/*
16 * Copyright (c) 2003,2004,2005 Armin Wolfermann
17 *
18 * Permission is hereby granted, free of charge, to any person obtaining a
19 * copy of this software and associated documentation files (the "Software"),
20 * to deal in the Software without restriction, including without limitation
21 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22 * and/or sell copies of the Software, and to permit persons to whom the
23 * Software is furnished to do so, subject to the following conditions:
24 *
25 * The above copyright notice and this permission notice shall be included in
26 * all copies or substantial portions of the Software.
27 *
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34 * DEALINGS IN THE SOFTWARE.
35 */
36#include "winutils.h"
37
38#include "proxy.h"
39#include "proxy_pollmgr.h"
40
41#include "lwip/sys.h"
42#include "lwip/tcpip.h"
43#include "lwip/udp.h"
44
45#ifndef RT_OS_WINDOWS
46#include <sys/poll.h>
47#include <sys/socket.h>
48#include <netinet/in.h>
49#include <netdb.h>
50#else
51#include "winpoll.h"
52#endif
53
54#include <stdio.h>
55#include <string.h>
56
57
58union sockaddr_inet {
59 struct sockaddr sa;
60 struct sockaddr_in sin;
61 struct sockaddr_in6 sin6;
62};
63
64
65struct request;
66
67
68/**
69 * DNS Proxy
70 */
71struct pxdns {
72 SOCKET sock4;
73 SOCKET sock6;
74
75 struct pollmgr_handler pmhdl4;
76 struct pollmgr_handler pmhdl6;
77
78 struct udp_pcb *pcb4;
79 struct udp_pcb *pcb6;
80
81 size_t generation;
82 size_t nresolvers;
83 union sockaddr_inet *resolvers;
84
85 u16_t id;
86
87 sys_mutex_t lock;
88
89 size_t active_queries;
90 size_t expired_queries;
91 size_t late_answers;
92 size_t hash_collisions;
93
94#define TIMEOUT 5
95 size_t timeout_slot;
96 struct request *timeout_list[TIMEOUT];
97
98#define HASHSIZE 10
99#define HASH(id) ((id) & ((1 << HASHSIZE) - 1))
100 struct request *request_hash[1 << HASHSIZE];
101} g_pxdns;
102
103
104struct request {
105 /**
106 * Request ID that we use in relayed request.
107 */
108 u16_t id;
109
110 /**
111 * pxdns::generation used for this request
112 */
113 size_t generation;
114
115 /**
116 * Current index into pxdns::resolvers
117 */
118 size_t residx;
119
120 /**
121 * PCB from which we have received this request. lwIP doesn't
122 * support listening for both IPv4 and IPv6 on the same pcb, so we
123 * use two and need to keep track.
124 */
125 struct udp_pcb *pcb;
126
127 /**
128 * Client this request is from and its original request ID.
129 */
130 ipX_addr_t client_addr;
131 u16_t client_port;
132 u16_t client_id;
133
134 /**
135 * Chaining for pxdns::request_hash
136 */
137 struct request **pprev_hash;
138 struct request *next_hash;
139
140 /**
141 * Chaining for pxdns::timeout_list
142 */
143 struct request **pprev_timeout;
144 struct request *next_timeout;
145
146 /**
147 * Pbuf with reply received on pollmgr thread.
148 */
149 struct pbuf *reply;
150
151 /**
152 * Preallocated lwIP message to send reply from the lwIP thread.
153 */
154 struct tcpip_msg msg_reply;
155
156 /**
157 * Client request. ID is replaced with ours, original saved in
158 * client_id. Use a copy since we might need to resend and we
159 * don't want to hold onto pbuf of the request.
160 */
161 size_t size;
162 u8_t data[1];
163};
164
165
166static void pxdns_create_resolver_sockaddrs(struct pxdns *pxdns,
167 const char **nameservers);
168
169static void pxdns_recv4(void *arg, struct udp_pcb *pcb, struct pbuf *p,
170 ip_addr_t *addr, u16_t port);
171static void pxdns_recv6(void *arg, struct udp_pcb *pcb, struct pbuf *p,
172 ip6_addr_t *addr, u16_t port);
173static void pxdns_query(struct pxdns *pxdns, struct udp_pcb *pcb, struct pbuf *p,
174 ipX_addr_t *addr, u16_t port);
175static void pxdns_timer(void *arg);
176static int pxdns_rexmit(struct pxdns *pxdns, struct request *req);
177static int pxdns_forward_outbound(struct pxdns *pxdns, struct request *req);
178
179static int pxdns_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents);
180static void pxdns_pcb_reply(void *ctx);
181
182static void pxdns_request_register(struct pxdns *pxdns, struct request *req);
183static void pxdns_request_deregister(struct pxdns *pxdns, struct request *req);
184static struct request *pxdns_request_find(struct pxdns *pxdns, u16_t id);
185
186static void pxdns_hash_add(struct pxdns *pxdns, struct request *req);
187static void pxdns_hash_del(struct pxdns *pxdns, struct request *req);
188static void pxdns_timeout_add(struct pxdns *pxdns, struct request *req);
189static void pxdns_timeout_del(struct pxdns *pxdns, struct request *req);
190
191static void pxdns_request_free(struct request *req);
192
193
194err_t
195pxdns_init(struct netif *proxy_netif)
196{
197 struct pxdns *pxdns = &g_pxdns;
198 err_t error;
199
200 LWIP_UNUSED_ARG(proxy_netif);
201
202 pxdns->pmhdl4.callback = pxdns_pmgr_pump;
203 pxdns->pmhdl4.data = (void *)pxdns;
204 pxdns->pmhdl4.slot = -1;
205
206 pxdns->pmhdl6.callback = pxdns_pmgr_pump;
207 pxdns->pmhdl6.data = (void *)pxdns;
208 pxdns->pmhdl6.slot = -1;
209
210 pxdns->pcb4 = udp_new();
211 if (pxdns->pcb4 == NULL) {
212 error = ERR_MEM;
213 goto err_cleanup_pcb;
214 }
215
216 pxdns->pcb6 = udp_new_ip6();
217 if (pxdns->pcb6 == NULL) {
218 error = ERR_MEM;
219 goto err_cleanup_pcb;
220 }
221
222 error = udp_bind(pxdns->pcb4, IP_ADDR_ANY, 53);
223 if (error != ERR_OK) {
224 goto err_cleanup_pcb;
225 }
226
227 error = udp_bind_ip6(pxdns->pcb6, IP6_ADDR_ANY, 53);
228 if (error != ERR_OK) {
229 goto err_cleanup_pcb;
230 }
231
232 udp_recv(pxdns->pcb4, pxdns_recv4, pxdns);
233 udp_recv_ip6(pxdns->pcb6, pxdns_recv6, pxdns);
234
235 pxdns->sock4 = socket(AF_INET, SOCK_DGRAM, 0);
236 if (pxdns->sock4 == INVALID_SOCKET) {
237 goto err_cleanup_pcb;
238 }
239
240 pxdns->sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
241 if (pxdns->sock6 == INVALID_SOCKET) {
242 /* it's ok if the host doesn't support IPv6 */
243 /* XXX: TODO: log */
244 }
245
246 pxdns->generation = 0;
247 pxdns->nresolvers = 0;
248 pxdns->resolvers = NULL;
249 pxdns_create_resolver_sockaddrs(pxdns, g_proxy_options->nameservers);
250
251 sys_mutex_new(&pxdns->lock);
252
253 pxdns->timeout_slot = 0;
254
255 /* NB: assumes pollmgr thread is not running yet */
256 pollmgr_add(&pxdns->pmhdl4, pxdns->sock4, POLLIN);
257 if (pxdns->sock6 != INVALID_SOCKET) {
258 pollmgr_add(&pxdns->pmhdl6, pxdns->sock6, POLLIN);
259 }
260
261 sys_timeout(1 * 1000, pxdns_timer, pxdns);
262
263 return ERR_OK;
264
265 err_cleanup_pcb:
266 if (pxdns->pcb4 != NULL) {
267 udp_remove(pxdns->pcb4);
268 pxdns->pcb4 = NULL;
269 }
270 if (pxdns->pcb6 != NULL) {
271 udp_remove(pxdns->pcb6);
272 pxdns->pcb4 = NULL;
273 }
274
275 return error;
276}
277
278
279/**
280 * lwIP thread callback to set the new list of nameservers.
281 */
282void
283pxdns_set_nameservers(void *arg)
284{
285 const char **nameservers = (const char **)arg;
286
287 if (g_proxy_options->nameservers != NULL) {
288 RTMemFree(g_proxy_options->nameservers);
289 }
290 g_proxy_options->nameservers = nameservers;
291
292 pxdns_create_resolver_sockaddrs(&g_pxdns, nameservers);
293}
294
295
296/**
297 * Use this list of nameservers to resolve guest requests.
298 *
299 * Runs on lwIP thread, so no new queries or retramsmits compete with
300 * it for the use of the existing list of resolvers (to be replaced).
301 */
302static void
303pxdns_create_resolver_sockaddrs(struct pxdns *pxdns, const char **nameservers)
304{
305 struct addrinfo hints;
306 union sockaddr_inet *resolvers;
307 size_t nnames, nresolvers;
308 const char **p;
309 int status;
310
311 resolvers = NULL;
312 nresolvers = 0;
313
314 if (nameservers == NULL) {
315 goto update_resolvers;
316 }
317
318 nnames = 0;
319 for (p = nameservers; *p != NULL; ++p) {
320 ++nnames;
321 }
322
323 if (nnames == 0) {
324 goto update_resolvers;
325 }
326
327 resolvers = (union sockaddr_inet *)calloc(sizeof(resolvers[0]), nnames);
328 if (resolvers == NULL) {
329 nresolvers = 0;
330 goto update_resolvers;
331 }
332
333 memset(&hints, 0, sizeof(hints));
334 hints.ai_family = AF_UNSPEC;
335 hints.ai_socktype = SOCK_DGRAM;
336 hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
337
338 for (p = nameservers; *p != NULL; ++p) {
339 const char *name = *p;
340 struct addrinfo *ai;
341 status = getaddrinfo(name, /* "domain" */ "53", &hints, &ai);
342 if (status != 0) {
343 /* XXX: log failed resolution */
344 continue;
345 }
346
347 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
348 /* XXX: log unsupported address family */
349 freeaddrinfo(ai);
350 continue;
351 }
352
353 if (ai->ai_addrlen > sizeof(resolvers[nresolvers])) {
354 /* XXX: log */
355 freeaddrinfo(ai);
356 continue;
357 }
358
359 if (ai->ai_family == AF_INET6 && pxdns->sock6 == INVALID_SOCKET) {
360 /* no IPv6 support on the host, can't use this resolver */
361 freeaddrinfo(ai);
362 continue;
363 }
364
365 memcpy(&resolvers[nresolvers], ai->ai_addr, ai->ai_addrlen);
366 freeaddrinfo(ai);
367 ++nresolvers;
368 }
369
370 if (nresolvers == 0) {
371 if (resolvers != NULL) {
372 free(resolvers);
373 }
374 resolvers = NULL;
375 }
376
377 update_resolvers:
378 ++pxdns->generation;
379 if (pxdns->resolvers != NULL) {
380 free(pxdns->resolvers);
381 }
382 pxdns->resolvers = resolvers;
383 pxdns->nresolvers = nresolvers;
384}
385
386
387static void
388pxdns_request_free(struct request *req)
389{
390 LWIP_ASSERT1(req->pprev_hash == NULL);
391 LWIP_ASSERT1(req->pprev_timeout == NULL);
392
393 if (req->reply != NULL) {
394 pbuf_free(req->reply);
395 }
396 free(req);
397}
398
399
400static void
401pxdns_hash_add(struct pxdns *pxdns, struct request *req)
402{
403 struct request **chain;
404
405 LWIP_ASSERT1(req->pprev_hash == NULL);
406 chain = &pxdns->request_hash[HASH(req->id)];
407 if ((req->next_hash = *chain) != NULL) {
408 (*chain)->pprev_hash = &req->next_hash;
409 ++pxdns->hash_collisions;
410 }
411 *chain = req;
412 req->pprev_hash = chain;
413}
414
415
416static void
417pxdns_timeout_add(struct pxdns *pxdns, struct request *req)
418{
419 struct request **chain;
420
421 LWIP_ASSERT1(req->pprev_timeout == NULL);
422 chain = &pxdns->timeout_list[pxdns->timeout_slot];
423 if ((req->next_timeout = *chain) != NULL) {
424 (*chain)->pprev_timeout = &req->next_timeout;
425 }
426 *chain = req;
427 req->pprev_timeout = chain;
428}
429
430
431static void
432pxdns_hash_del(struct pxdns *pxdns, struct request *req)
433{
434 LWIP_ASSERT1(req->pprev_hash != NULL);
435 --pxdns->active_queries;
436
437 if (req->next_hash != NULL) {
438 req->next_hash->pprev_hash = req->pprev_hash;
439 }
440 *req->pprev_hash = req->next_hash;
441 req->pprev_hash = NULL;
442 req->next_hash = NULL;
443}
444
445
446static void
447pxdns_timeout_del(struct pxdns *pxdns, struct request *req)
448{
449 LWIP_ASSERT1(req->pprev_timeout != NULL);
450
451 if (req->next_timeout != NULL) {
452 req->next_timeout->pprev_timeout = req->pprev_timeout;
453 }
454 *req->pprev_timeout = req->next_timeout;
455 req->pprev_timeout = NULL;
456 req->next_timeout = NULL;
457}
458
459
460
461/**
462 * Do bookkeeping on new request. Called from pxdns_query().
463 */
464static void
465pxdns_request_register(struct pxdns *pxdns, struct request *req)
466{
467 sys_mutex_lock(&pxdns->lock);
468
469 pxdns_hash_add(pxdns, req);
470 pxdns_timeout_add(pxdns, req);
471 ++pxdns->active_queries;
472
473 sys_mutex_unlock(&pxdns->lock);
474}
475
476
477static void
478pxdns_request_deregister(struct pxdns *pxdns, struct request *req)
479{
480 sys_mutex_lock(&pxdns->lock);
481
482 pxdns_hash_del(pxdns, req);
483 pxdns_timeout_del(pxdns, req);
484 --pxdns->active_queries;
485
486 sys_mutex_unlock(&pxdns->lock);
487}
488
489
490/**
491 * Find request by the id we used when relaying it and remove it from
492 * id hash and timeout list. Called from pxdns_pmgr_pump() when reply
493 * comes.
494 */
495static struct request *
496pxdns_request_find(struct pxdns *pxdns, u16_t id)
497{
498 struct request *req = NULL;
499
500 sys_mutex_lock(&pxdns->lock);
501
502 /* find request in the id->req hash */
503 for (req = pxdns->request_hash[HASH(id)]; req != NULL; req = req->next_hash) {
504 if (req->id == id) {
505 break;
506 }
507 }
508
509 if (req != NULL) {
510 pxdns_hash_del(pxdns, req);
511 pxdns_timeout_del(pxdns, req);
512 --pxdns->active_queries;
513 }
514
515 sys_mutex_unlock(&pxdns->lock);
516 return req;
517}
518
519
520/**
521 * Retransmit of g/c expired requests and move timeout slot forward.
522 */
523static void
524pxdns_timer(void *arg)
525{
526 struct pxdns *pxdns = (struct pxdns *)arg;
527 struct request **chain, *req;
528
529 sys_mutex_lock(&pxdns->lock);
530
531 /*
532 * Move timeout slot first. New slot points to the list of
533 * expired requests. If any expired request is retransmitted, we
534 * keep it on the list (that is now current), effectively
535 * resetting the timeout.
536 */
537 LWIP_ASSERT1(pxdns->timeout_slot < TIMEOUT);
538 if (++pxdns->timeout_slot == TIMEOUT) {
539 pxdns->timeout_slot = 0;
540 }
541
542 chain = &pxdns->timeout_list[pxdns->timeout_slot];
543 req = *chain;
544 while (req != NULL) {
545 struct request *expired = req;
546 req = req->next_timeout;
547
548 if (pxdns_rexmit(pxdns, expired)) {
549 continue;
550 }
551
552 pxdns_hash_del(pxdns, expired);
553 pxdns_timeout_del(pxdns, expired);
554 ++pxdns->expired_queries;
555
556 pxdns_request_free(expired);
557 }
558
559 sys_mutex_unlock(&pxdns->lock);
560
561 sys_timeout(1 * 1000, pxdns_timer, pxdns);
562}
563
564
565static void
566pxdns_recv4(void *arg, struct udp_pcb *pcb, struct pbuf *p,
567 ip_addr_t *addr, u16_t port)
568{
569 struct pxdns *pxdns = (struct pxdns *)arg;
570 pxdns_query(pxdns, pcb, p, ip_2_ipX(addr), port);
571}
572
573static void
574pxdns_recv6(void *arg, struct udp_pcb *pcb, struct pbuf *p,
575 ip6_addr_t *addr, u16_t port)
576{
577 struct pxdns *pxdns = (struct pxdns *)arg;
578 pxdns_query(pxdns, pcb, p, ip6_2_ipX(addr), port);
579}
580
581
582static void
583pxdns_query(struct pxdns *pxdns, struct udp_pcb *pcb, struct pbuf *p,
584 ipX_addr_t *addr, u16_t port)
585{
586 struct request *req;
587 int sent;
588
589 if (pxdns->nresolvers == 0) {
590 /* nothing we can do */
591 pbuf_free(p);
592 return;
593 }
594
595 req = calloc(1, sizeof(struct request) - 1 + p->tot_len);
596 if (req == NULL) {
597 pbuf_free(p);
598 return;
599 }
600
601 /* copy request data */
602 req->size = p->tot_len;
603 pbuf_copy_partial(p, req->data, p->tot_len, 0);
604
605 /* save client identity and client's request id */
606 req->pcb = pcb;
607 ipX_addr_copy(PCB_ISIPV6(pcb), req->client_addr, *addr);
608 req->client_port = port;
609 memcpy(&req->client_id, req->data, sizeof(req->client_id));
610
611 /* slap our request id onto it */
612 req->id = pxdns->id++;
613 memcpy(req->data, &req->id, sizeof(u16_t));
614
615 /* resolver to forward to */
616 req->generation = pxdns->generation;
617 req->residx = 0;
618
619 /* prepare for relaying the reply back to guest */
620 req->msg_reply.type = TCPIP_MSG_CALLBACK_STATIC;
621 req->msg_reply.sem = NULL;
622 req->msg_reply.msg.cb.function = pxdns_pcb_reply;
623 req->msg_reply.msg.cb.ctx = (void *)req;
624
625 DPRINTF2(("%s: req=%p: client id %d -> id %d\n",
626 __func__, (void *)req, req->client_id, req->id));
627
628 pxdns_request_register(pxdns, req);
629
630 sent = pxdns_forward_outbound(pxdns, req);
631 if (!sent) {
632 sent = pxdns_rexmit(pxdns, req);
633 }
634 if (!sent) {
635 pxdns_request_deregister(pxdns, req);
636 pxdns_request_free(req);
637 }
638}
639
640
641/**
642 * Forward request to the req::residx resolver in the pxdns::resolvers
643 * array of upstream resolvers.
644 *
645 * Returns 1 on success, 0 on failure.
646 */
647static int
648pxdns_forward_outbound(struct pxdns *pxdns, struct request *req)
649{
650 union sockaddr_inet *resolver;
651 ssize_t nsent;
652
653 DPRINTF2(("%s: req %p: sending to resolver #%lu\n",
654 __func__, (void *)req, (unsigned long)req->residx));
655
656 LWIP_ASSERT1(req->generation == pxdns->generation);
657 LWIP_ASSERT1(req->residx < pxdns->nresolvers);
658 resolver = &pxdns->resolvers[req->residx];
659
660 if (resolver->sa.sa_family == AF_INET) {
661 nsent = sendto(pxdns->sock4, req->data, req->size, 0,
662 &resolver->sa, sizeof(resolver->sin));
663
664 }
665 else if (resolver->sa.sa_family == AF_INET6) {
666 if (pxdns->sock6 != INVALID_SOCKET) {
667 nsent = sendto(pxdns->sock6, req->data, req->size, 0,
668 &resolver->sa, sizeof(resolver->sin6));
669 }
670 else {
671 /* shouldn't happen, we should have weeded out IPv6 resolvers */
672 return 0;
673 }
674 }
675 else {
676 /* shouldn't happen, we should have weeded out unsupported families */
677 return 0;
678 }
679
680 if ((size_t)nsent == req->size) {
681 return 1; /* sent */
682 }
683
684 if (nsent < 0) {
685 DPRINTF2(("%s: send: errno %d\n", __func__, errno));
686 }
687 else {
688 DPRINTF2(("%s: sent only %lu of %lu\n",
689 __func__, (unsigned long)nsent, (unsigned long)req->size));
690 }
691 return 0; /* not sent, caller will retry as necessary */
692}
693
694
695/**
696 * Forward request to the next resolver in the pxdns::resolvers array
697 * of upstream resolvers if there are any left.
698 */
699static int
700pxdns_rexmit(struct pxdns *pxdns, struct request *req)
701{
702 int sent;
703
704 if (/* __predict_false */ req->generation != pxdns->generation) {
705 DPRINTF2(("%s: req %p: generation %lu != pxdns generation %lu\n",
706 __func__, (void *)req,
707 (unsigned long)req->generation,
708 (unsigned long)pxdns->generation));
709 return 0;
710 }
711
712 LWIP_ASSERT1(req->residx < pxdns->nresolvers);
713 do {
714 if (++req->residx == pxdns->nresolvers) {
715 return 0;
716 }
717
718 sent = pxdns_forward_outbound(pxdns, req);
719 } while (!sent);
720
721 return 1;
722}
723
724
725static int
726pxdns_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents)
727{
728 struct pxdns *pxdns;
729 struct request *req;
730 ssize_t nread;
731 err_t error;
732 u16_t id;
733
734 pxdns = (struct pxdns *)handler->data;
735 LWIP_ASSERT1(handler == &pxdns->pmhdl4 || handler == &pxdns->pmhdl6);
736 LWIP_ASSERT1(fd == (handler == &pxdns->pmhdl4 ? pxdns->sock4 : pxdns->sock6));
737
738 if (revents & ~(POLLIN|POLLERR)) {
739 DPRINTF0(("%s: unexpected revents 0x%x\n", __func__, revents));
740 return POLLIN;
741 }
742
743 if (revents & POLLERR) {
744 int sockerr = -1;
745 socklen_t optlen = (socklen_t)sizeof(sockerr);
746 int status;
747
748 status = getsockopt(fd, SOL_SOCKET,
749 SO_ERROR, (char *)&sockerr, &optlen);
750 if (status < 0) {
751 DPRINTF(("%s: sock %d: SO_ERROR failed with errno %d\n",
752 __func__, fd, errno));
753 }
754 else {
755 DPRINTF(("%s: sock %d: errno %d\n",
756 __func__, fd, sockerr));
757 }
758 }
759
760 if ((revents & POLLIN) == 0) {
761 return POLLIN;
762 }
763
764
765 nread = recv(fd, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0);
766 if (nread < 0) {
767 perror(__func__);
768 return POLLIN;
769 }
770
771 /* check for minimum dns packet length */
772 if (nread < 12) {
773 DPRINTF2(("%s: short reply %lu bytes\n",
774 __func__, (unsigned long)nread));
775 return POLLIN;
776 }
777
778 /* XXX: shall we proxy back RCODE=Refused responses? */
779
780 memcpy(&id, pollmgr_udpbuf, sizeof(id));
781 req = pxdns_request_find(pxdns, id);
782 if (req == NULL) {
783 DPRINTF2(("%s: orphaned reply for %d\n", __func__, id));
784 ++pxdns->late_answers;
785 return POLLIN;
786 }
787
788 DPRINTF2(("%s: reply for req=%p: id %d -> client id %d\n",
789 __func__, (void *)req, req->id, req->client_id));
790
791 req->reply = pbuf_alloc(PBUF_RAW, nread, PBUF_RAM);
792 if (req->reply == NULL) {
793 DPRINTF(("%s: pbuf_alloc(%d) failed\n", __func__, (int)nread));
794 pxdns_request_free(req);
795 return POLLIN;
796 }
797
798 memcpy(pollmgr_udpbuf, &req->client_id, sizeof(req->client_id));
799 error = pbuf_take(req->reply, pollmgr_udpbuf, nread);
800 if (error != ERR_OK) {
801 DPRINTF(("%s: pbuf_take(%d) failed\n", __func__, (int)nread));
802 pxdns_request_free(req);
803 return POLLIN;
804 }
805
806 proxy_lwip_post(&req->msg_reply);
807 return POLLIN;
808}
809
810
811/**
812 * Called on lwIP thread via request::msg_reply callback.
813 */
814static void
815pxdns_pcb_reply(void *ctx)
816{
817 struct request *req = (struct request *)ctx;
818 err_t error;
819
820 error = udp_sendto(req->pcb, req->reply,
821 ipX_2_ip(&req->client_addr), req->client_port);
822 if (error != ERR_OK) {
823 DPRINTF(("%s: udp_sendto err %s\n",
824 __func__, proxy_lwip_strerr(error)));
825 }
826
827 pxdns_request_free(req);
828}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette