VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/pxudp.c@ 50213

最後變更 在這個檔案從50213是 50022,由 vboxsync 提交於 11 年 前

Don't call pbuf_free() in proxy_sendto(), leave it up to the caller
that may still need the pbuf, e.g. to generate an ICMP error.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 15.9 KB
 
1/* -*- indent-tabs-mode: nil; -*- */
2
3#include "winutils.h"
4#include "proxy.h"
5#include "proxy_pollmgr.h"
6#include "pxremap.h"
7
8#ifndef RT_OS_WINDOWS
9#include <sys/types.h>
10#include <sys/socket.h>
11#include <stdlib.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <poll.h>
15
16#include <err.h> /* BSD'ism */
17#else
18#include <stdlib.h>
19#include <iprt/stdint.h>
20#include <stdio.h>
21#include "winpoll.h"
22#endif
23
24#include "lwip/opt.h"
25
26#include "lwip/sys.h"
27#include "lwip/tcpip.h"
28#include "lwip/udp.h"
29
30struct pxudp {
31 /**
32 * Our poll manager handler.
33 */
34 struct pollmgr_handler pmhdl;
35
36 /**
37 * lwIP ("internal") side of the proxied connection.
38 */
39 struct udp_pcb *pcb;
40
41 /**
42 * Host ("external") side of the proxied connection.
43 */
44 SOCKET sock;
45
46 /**
47 * For some protocols (notably: DNS) we know we are getting just
48 * one reply, so we don't want the pcb and the socket to sit there
49 * waiting to be g/c'ed by timeout. This field counts request and
50 * replies for them.
51 */
52 int count;
53
54 /**
55 * Mailbox for inbound pbufs.
56 *
57 * XXX: since we have single producer and single consumer we can
58 * use lockless ringbuf like for pxtcp.
59 */
60 sys_mbox_t inmbox;
61
62 /**
63 * lwIP thread's strong reference to us.
64 */
65 struct pollmgr_refptr *rp;
66
67 /*
68 * We use static messages to void malloc/free overhead.
69 */
70 struct tcpip_msg msg_delete; /* delete pxudp */
71 struct tcpip_msg msg_inbound; /* trigger send of inbound data */
72};
73
74
75static struct pxudp *pxudp_allocate(void);
76static void pxudp_drain_inmbox(struct pxudp *);
77static void pxudp_free(struct pxudp *);
78
79static struct udp_pcb *pxudp_pcb_dissociate(struct pxudp *);
80
81/* poll manager callbacks for pxudp related channels */
82static int pxudp_pmgr_chan_add(struct pollmgr_handler *, SOCKET, int);
83static int pxudp_pmgr_chan_del(struct pollmgr_handler *, SOCKET, int);
84
85/* helper functions for sending/receiving pxudp over poll manager channels */
86static ssize_t pxudp_chan_send(enum pollmgr_slot_t, struct pxudp *);
87static ssize_t pxudp_chan_send_weak(enum pollmgr_slot_t, struct pxudp *);
88static struct pxudp *pxudp_chan_recv(struct pollmgr_handler *, SOCKET, int);
89static struct pxudp *pxudp_chan_recv_strong(struct pollmgr_handler *, SOCKET, int);
90
91/* poll manager callbacks for individual sockets */
92static int pxudp_pmgr_pump(struct pollmgr_handler *, SOCKET, int);
93
94/* convenience function for poll manager callback */
95static int pxudp_schedule_delete(struct pxudp *);
96
97/* lwip thread callbacks called via proxy_lwip_post() */
98static void pxudp_pcb_delete_pxudp(void *);
99
100/* udp pcb callbacks &c */
101static void pxudp_pcb_accept(void *, struct udp_pcb *, struct pbuf *, ip_addr_t *, u16_t);
102static void pxudp_pcb_recv(void *, struct udp_pcb *, struct pbuf *, ip_addr_t *, u16_t);
103static void pxudp_pcb_forward_outbound(struct pxudp *, struct pbuf *, ip_addr_t *, u16_t);
104static void pxudp_pcb_expired(struct pxudp *);
105static void pxudp_pcb_write_inbound(void *);
106static void pxudp_pcb_forward_inbound(struct pxudp *);
107
108/* poll manager handlers for pxudp channels */
109static struct pollmgr_handler pxudp_pmgr_chan_add_hdl;
110static struct pollmgr_handler pxudp_pmgr_chan_del_hdl;
111
112
113void
114pxudp_init(void)
115{
116 /*
117 * Create channels.
118 */
119 pxudp_pmgr_chan_add_hdl.callback = pxudp_pmgr_chan_add;
120 pxudp_pmgr_chan_add_hdl.data = NULL;
121 pxudp_pmgr_chan_add_hdl.slot = -1;
122 pollmgr_add_chan(POLLMGR_CHAN_PXUDP_ADD, &pxudp_pmgr_chan_add_hdl);
123
124 pxudp_pmgr_chan_del_hdl.callback = pxudp_pmgr_chan_del;
125 pxudp_pmgr_chan_del_hdl.data = NULL;
126 pxudp_pmgr_chan_del_hdl.slot = -1;
127 pollmgr_add_chan(POLLMGR_CHAN_PXUDP_DEL, &pxudp_pmgr_chan_del_hdl);
128
129 udp_proxy_accept(pxudp_pcb_accept);
130}
131
132
133/**
134 * Syntactic sugar for sending pxudp pointer over poll manager
135 * channel. Used by lwip thread functions.
136 */
137static ssize_t
138pxudp_chan_send(enum pollmgr_slot_t chan, struct pxudp *pxudp)
139{
140 return pollmgr_chan_send(chan, &pxudp, sizeof(pxudp));
141}
142
143
144/**
145 * Syntactic sugar for sending weak reference to pxudp over poll
146 * manager channel. Used by lwip thread functions.
147 */
148static ssize_t
149pxudp_chan_send_weak(enum pollmgr_slot_t chan, struct pxudp *pxudp)
150{
151 pollmgr_refptr_weak_ref(pxudp->rp);
152 return pollmgr_chan_send(chan, &pxudp->rp, sizeof(pxudp->rp));
153}
154
155
156/**
157 * Counterpart of pxudp_chan_send().
158 */
159static struct pxudp *
160pxudp_chan_recv(struct pollmgr_handler *handler, SOCKET fd, int revents)
161{
162 struct pxudp *pxudp;
163
164 pxudp = (struct pxudp *)pollmgr_chan_recv_ptr(handler, fd, revents);
165 return pxudp;
166}
167
168
169/**
170 * Counterpart of pxudp_chan_send_weak().
171 */
172struct pxudp *
173pxudp_chan_recv_strong(struct pollmgr_handler *handler, SOCKET fd, int revents)
174{
175 struct pollmgr_refptr *rp;
176 struct pollmgr_handler *base;
177 struct pxudp *pxudp;
178
179 rp = (struct pollmgr_refptr *)pollmgr_chan_recv_ptr(handler, fd, revents);
180 base = (struct pollmgr_handler *)pollmgr_refptr_get(rp);
181 pxudp = (struct pxudp *)base;
182
183 return pxudp;
184}
185
186
187/**
188 * POLLMGR_CHAN_PXUDP_ADD handler.
189 *
190 * Get new pxudp from lwip thread and start polling its socket.
191 */
192static int
193pxudp_pmgr_chan_add(struct pollmgr_handler *handler, SOCKET fd, int revents)
194{
195 struct pxudp *pxudp;
196 int status;
197
198 pxudp = pxudp_chan_recv(handler, fd, revents);
199 DPRINTF(("pxudp_add: new pxudp %p; pcb %p\n",
200 (void *)pxudp, (void *)pxudp->pcb));
201
202 LWIP_ASSERT1(pxudp != NULL);
203 LWIP_ASSERT1(pxudp->pmhdl.callback != NULL);
204 LWIP_ASSERT1(pxudp->pmhdl.data = (void *)pxudp);
205 LWIP_ASSERT1(pxudp->pmhdl.slot < 0);
206
207
208 status = pollmgr_add(&pxudp->pmhdl, pxudp->sock, POLLIN);
209 if (status < 0) {
210 pxudp_schedule_delete(pxudp);
211 }
212
213 return POLLIN;
214}
215
216
217/**
218 * POLLMGR_CHAN_PXUDP_DEL handler.
219 */
220static int
221pxudp_pmgr_chan_del(struct pollmgr_handler *handler, SOCKET fd, int revents)
222{
223 struct pxudp *pxudp;
224
225 pxudp = pxudp_chan_recv_strong(handler, fd, revents);
226 if (pxudp == NULL) {
227 return POLLIN;
228 }
229
230 DPRINTF(("pxudp_del: pxudp %p; socket %d\n", (void *)pxudp, pxudp->sock));
231
232 pollmgr_del_slot(pxudp->pmhdl.slot);
233
234 /*
235 * Go back to lwip thread to delete after any pending callbacks
236 * for unprocessed inbound traffic are drained.
237 */
238 pxudp_schedule_delete(pxudp);
239
240 return POLLIN;
241}
242
243
244static struct pxudp *
245pxudp_allocate(void)
246{
247 struct pxudp *pxudp;
248 err_t error;
249
250 pxudp = (struct pxudp *)malloc(sizeof(*pxudp));
251 if (pxudp == NULL) {
252 return NULL;
253 }
254
255 pxudp->pmhdl.callback = NULL;
256 pxudp->pmhdl.data = (void *)pxudp;
257 pxudp->pmhdl.slot = -1;
258
259 pxudp->pcb = NULL;
260 pxudp->sock = INVALID_SOCKET;
261 pxudp->count = 0;
262
263 pxudp->rp = pollmgr_refptr_create(&pxudp->pmhdl);
264 if (pxudp->rp == NULL) {
265 free(pxudp);
266 return NULL;
267 }
268
269 error = sys_mbox_new(&pxudp->inmbox, 16);
270 if (error != ERR_OK) {
271 pollmgr_refptr_unref(pxudp->rp);
272 free(pxudp);
273 return NULL;
274 }
275
276#define CALLBACK_MSG(MSG, FUNC) \
277 do { \
278 pxudp->MSG.type = TCPIP_MSG_CALLBACK_STATIC; \
279 pxudp->MSG.sem = NULL; \
280 pxudp->MSG.msg.cb.function = FUNC; \
281 pxudp->MSG.msg.cb.ctx = (void *)pxudp; \
282 } while (0)
283
284 CALLBACK_MSG(msg_delete, pxudp_pcb_delete_pxudp);
285 CALLBACK_MSG(msg_inbound, pxudp_pcb_write_inbound);
286
287 return pxudp;
288}
289
290
291static void
292pxudp_drain_inmbox(struct pxudp *pxudp)
293{
294 void *ptr;
295
296 if (!sys_mbox_valid(&pxudp->inmbox)) {
297 return;
298 }
299
300 while (sys_mbox_tryfetch(&pxudp->inmbox, &ptr) != SYS_MBOX_EMPTY) {
301 struct pbuf *p = (struct pbuf *)ptr;
302 pbuf_free(p);
303 }
304
305 sys_mbox_free(&pxudp->inmbox);
306 sys_mbox_set_invalid(&pxudp->inmbox);
307}
308
309
310static void
311pxudp_free(struct pxudp *pxudp)
312{
313 pxudp_drain_inmbox(pxudp);
314 free(pxudp);
315}
316
317
318/**
319 * Dissociate pxudp and its udp_pcb.
320 *
321 * Unlike its TCP cousin returns the pcb since UDP pcbs need to be
322 * actively deleted, so save callers the trouble of saving a copy
323 * before calling us.
324 */
325static struct udp_pcb *
326pxudp_pcb_dissociate(struct pxudp *pxudp)
327{
328 struct udp_pcb *pcb;
329
330 if (pxudp == NULL || pxudp->pcb == NULL) {
331 return NULL;
332 }
333
334 pcb = pxudp->pcb;
335
336 udp_recv(pxudp->pcb, NULL, NULL);
337 pxudp->pcb = NULL;
338
339 return pcb;
340}
341
342
343/**
344 * Lwip thread callback invoked via pxudp::msg_delete
345 *
346 * Since we use static messages to communicate to the lwip thread, we
347 * cannot delete pxudp without making sure there are no unprocessed
348 * messages in the lwip thread mailbox.
349 *
350 * The easiest way to ensure that is to send this "delete" message as
351 * the last one and when it's processed we know there are no more and
352 * it's safe to delete pxudp.
353 *
354 * Channel callback should use pxudp_schedule_delete() convenience
355 * function defined below.
356 */
357static void
358pxudp_pcb_delete_pxudp(void *arg)
359{
360 struct pxudp *pxudp = (struct pxudp *)arg;
361 struct udp_pcb *pcb;
362
363 LWIP_ASSERT1(pxudp != NULL);
364
365 if (pxudp->sock != INVALID_SOCKET) {
366 closesocket(pxudp->sock);
367 pxudp->sock = INVALID_SOCKET;
368 }
369
370 pcb = pxudp_pcb_dissociate(pxudp);
371 if (pcb != NULL) {
372 udp_remove(pcb);
373 }
374
375 pollmgr_refptr_unref(pxudp->rp);
376 pxudp_free(pxudp);
377}
378
379
380/**
381 * Poll manager callback should use this convenience wrapper to
382 * schedule pxudp deletion on the lwip thread and to deregister from
383 * the poll manager.
384 */
385static int
386pxudp_schedule_delete(struct pxudp *pxudp)
387{
388 /*
389 * If pollmgr_refptr_get() is called by any channel before
390 * scheduled deletion happens, let them know we are gone.
391 */
392 pxudp->pmhdl.slot = -1;
393
394 /*
395 * Schedule deletion. Since poll manager thread may be pre-empted
396 * right after we send the message, the deletion may actually
397 * happen on the lwip thread before we return from this function,
398 * so it's not safe to refer to pxudp after this call.
399 */
400 proxy_lwip_post(&pxudp->msg_delete);
401
402 /* tell poll manager to deregister us */
403 return -1;
404}
405
406
407/**
408 * New proxied UDP conversation created.
409 * Global callback for udp_proxy_accept().
410 */
411static void
412pxudp_pcb_accept(void *arg, struct udp_pcb *newpcb, struct pbuf *p,
413 ip_addr_t *addr, u16_t port)
414{
415 struct pxudp *pxudp;
416 ipX_addr_t dst_addr;
417 int mapping;
418 int sdom;
419 SOCKET sock;
420
421 LWIP_ASSERT1(newpcb != NULL);
422 LWIP_ASSERT1(p != NULL);
423 LWIP_UNUSED_ARG(arg);
424
425 pxudp = pxudp_allocate();
426 if (pxudp == NULL) {
427 DPRINTF(("pxudp_allocate: failed\n"));
428 udp_remove(newpcb);
429 pbuf_free(p);
430 return;
431 }
432
433 sdom = PCB_ISIPV6(newpcb) ? PF_INET6 : PF_INET;
434 mapping = pxremap_outbound_ipX(PCB_ISIPV6(newpcb), &dst_addr, &newpcb->local_ip);
435
436#if 0 /* XXX: DNS IPv6->IPv4 remapping hack */
437 if (mapping == PXREMAP_MAPPED
438 && newpcb->local_port == 53
439 && PCB_ISIPV6(newpcb))
440 {
441 /*
442 * "Remap" DNS over IPv6 to IPv4 since Ubuntu dnsmasq does not
443 * listen on IPv6.
444 */
445 sdom = PF_INET;
446 ipX_addr_set_loopback(0, &dst_addr);
447 }
448#endif /* DNS IPv6->IPv4 remapping hack */
449
450 sock = proxy_connected_socket(sdom, SOCK_DGRAM,
451 &dst_addr, newpcb->local_port);
452 if (sock == INVALID_SOCKET) {
453 udp_remove(newpcb);
454 pbuf_free(p);
455 return;
456 }
457
458 pxudp->sock = sock;
459 pxudp->pcb = newpcb;
460 udp_recv(newpcb, pxudp_pcb_recv, pxudp);
461
462 pxudp->pmhdl.callback = pxudp_pmgr_pump;
463 pxudp_chan_send(POLLMGR_CHAN_PXUDP_ADD, pxudp);
464
465 /* dispatch directly instead of calling pxudp_pcb_recv() */
466 pxudp_pcb_forward_outbound(pxudp, p, addr, port);
467}
468
469
470/**
471 * udp_recv() callback.
472 */
473static void
474pxudp_pcb_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
475 ip_addr_t *addr, u16_t port)
476{
477 struct pxudp *pxudp = (struct pxudp *)arg;
478
479 LWIP_ASSERT1(pxudp != NULL);
480 LWIP_ASSERT1(pcb == pxudp->pcb);
481 LWIP_UNUSED_ARG(pcb);
482
483 if (p != NULL) {
484 pxudp_pcb_forward_outbound(pxudp, p, addr, port);
485 }
486 else {
487 pxudp_pcb_expired(pxudp);
488 }
489}
490
491
492static void
493pxudp_pcb_forward_outbound(struct pxudp *pxudp, struct pbuf *p,
494 ip_addr_t *addr, u16_t port)
495{
496 LWIP_UNUSED_ARG(addr);
497 LWIP_UNUSED_ARG(port);
498
499 if (pxudp->pcb->local_port == 53) {
500 ++pxudp->count;
501 }
502
503 proxy_sendto(pxudp->sock, p, NULL, 0);
504 pbuf_free(p);
505}
506
507
508/**
509 * Proxy udp_pcbs are expired by timer, which is signaled by passing
510 * NULL pbuf to the udp_recv() callback. At that point the pcb is
511 * removed from the list of proxy udp pcbs so no new datagrams will be
512 * delivered.
513 */
514static void
515pxudp_pcb_expired(struct pxudp *pxudp)
516{
517 struct udp_pcb *pcb;
518
519 DPRINTF2(("%s: pxudp %p, pcb %p, sock %d: expired\n",
520 __func__, (void *)pxudp, (void *)pxudp->pcb, pxudp->sock));
521
522 pcb = pxudp_pcb_dissociate(pxudp);
523 if (pcb != NULL) {
524 udp_remove(pcb);
525 }
526
527 pxudp_chan_send_weak(POLLMGR_CHAN_PXUDP_DEL, pxudp);
528}
529
530
531/**
532 */
533static int
534pxudp_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents)
535{
536 struct pxudp *pxudp;
537 struct pbuf *p;
538 ssize_t nread;
539 err_t error;
540
541 pxudp = (struct pxudp *)handler->data;
542 LWIP_ASSERT1(handler == &pxudp->pmhdl);
543 LWIP_ASSERT1(fd == pxudp->sock);
544 LWIP_UNUSED_ARG(fd);
545
546
547 if (revents & ~(POLLIN|POLLERR)) {
548 DPRINTF(("%s: unexpected revents 0x%x\n", __func__, revents));
549 return pxudp_schedule_delete(pxudp);
550 }
551
552 /*
553 * XXX: AFAICS, there's no way to match the error with the
554 * outgoing datagram that triggered it, since we do non-blocking
555 * sends from lwip thread.
556 */
557 if (revents & POLLERR) {
558 int sockerr = -1;
559 socklen_t optlen = (socklen_t)sizeof(sockerr);
560 int status;
561
562 status = getsockopt(pxudp->sock, SOL_SOCKET,
563 SO_ERROR, (char *)&sockerr, &optlen);
564 if (status < 0) {
565 DPRINTF(("%s: sock %d: SO_ERROR failed with errno %d\n",
566 __func__, pxudp->sock, errno));
567 }
568 else {
569 DPRINTF(("%s: sock %d: errno %d\n",
570 __func__, pxudp->sock, sockerr));
571 }
572 }
573
574 if ((revents & POLLIN) == 0) {
575 return POLLIN;
576 }
577
578 nread = recv(pxudp->sock, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0);
579 if (nread == SOCKET_ERROR) {
580 perror(__func__);
581 return POLLIN;
582 }
583
584 p = pbuf_alloc(PBUF_RAW, (u16_t)nread, PBUF_RAM);
585 if (p == NULL) {
586 DPRINTF(("%s: pbuf_alloc(%d) failed\n", __func__, (int)nread));
587 return POLLIN;
588 }
589
590 error = pbuf_take(p, pollmgr_udpbuf, (u16_t)nread);
591 if (error != ERR_OK) {
592 DPRINTF(("%s: pbuf_take(%d) failed\n", __func__, (int)nread));
593 pbuf_free(p);
594 return POLLIN;
595 }
596
597 error = sys_mbox_trypost(&pxudp->inmbox, p);
598 if (error != ERR_OK) {
599 pbuf_free(p);
600 return POLLIN;
601 }
602
603 proxy_lwip_post(&pxudp->msg_inbound);
604
605 return POLLIN;
606}
607
608
609/**
610 * Callback from poll manager to trigger sending to guest.
611 */
612static void
613pxudp_pcb_write_inbound(void *ctx)
614{
615 struct pxudp *pxudp = (struct pxudp *)ctx;
616 LWIP_ASSERT1(pxudp != NULL);
617
618 if (pxudp->pcb == NULL) {
619 return;
620 }
621
622 pxudp_pcb_forward_inbound(pxudp);
623}
624
625
626static void
627pxudp_pcb_forward_inbound(struct pxudp *pxudp)
628{
629 struct pbuf *p;
630 u32_t timo;
631 err_t error;
632
633 if (!sys_mbox_valid(&pxudp->inmbox)) {
634 return;
635 }
636
637 timo = sys_mbox_tryfetch(&pxudp->inmbox, (void **)&p);
638 if (timo == SYS_MBOX_EMPTY) {
639 return;
640 }
641
642 error = udp_send(pxudp->pcb, p);
643 if (error != ERR_OK) {
644 DPRINTF(("%s: udp_send(pcb %p) err %d\n",
645 __func__, (void *)pxudp, error));
646 }
647
648 pbuf_free(p);
649
650 /*
651 * If we enabled counting in pxudp_pcb_forward_outbound() check
652 * that we have (all) the reply(s).
653 */
654 if (pxudp->count > 0) {
655 --pxudp->count;
656 if (pxudp->count == 0) {
657 pxudp_pcb_expired(pxudp);
658 }
659 }
660}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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