VirtualBox

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

最後變更 在這個檔案從107689是 107629,由 vboxsync 提交於 2 月 前

NetworkServices/NAT/pxdns.c: Replace redundant condition with assertion, resolvers should always be != NULL at this point, bugref:3409

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

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