VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/fwudp.c@ 51574

最後變更 在這個檔案從51574是 51574,由 vboxsync 提交於 10 年 前

NAT/Net: #define LOG_GROUP LOG_GROUP_NAT_SERVICE

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 12.3 KB
 
1/* -*- indent-tabs-mode: nil; -*- */
2#define LOG_GROUP LOG_GROUP_NAT_SERVICE
3
4#include "winutils.h"
5#include "proxy.h"
6#include "proxy_pollmgr.h"
7#include "portfwd.h"
8#include "pxremap.h"
9
10#ifndef RT_OS_WINDOWS
11#include <sys/types.h>
12#include <sys/socket.h>
13#include <stdio.h>
14#include <string.h>
15#include <poll.h>
16
17#include <err.h> /* BSD'ism */
18#else
19#include <stdio.h>
20#include <string.h>
21#include "winpoll.h"
22#endif
23
24#include "lwip/opt.h"
25#include "lwip/memp.h" /* XXX: for bulk delete of pcbs */
26
27#include "lwip/sys.h"
28#include "lwip/tcpip.h"
29#include "lwip/udp.h"
30
31struct fwudp_dgram {
32 struct pbuf *p;
33 ipX_addr_t src_addr;
34 u16_t src_port;
35};
36
37/**
38 * UDP port-forwarding.
39 *
40 * Unlike pxudp that uses 1:1 mapping between pcb and socket, for
41 * port-forwarded UDP the setup is bit more elaborated.
42 *
43 * For fwtcp things are simple since incoming TCP connection get a new
44 * socket that we just hand off to pxtcp. Thus fwtcp only handles
45 * connection initiation.
46 *
47 * For fwudp all proxied UDP conversations share the same socket, so
48 * single fwudp multiplexes to several UDP pcbs.
49 *
50 * XXX: TODO: Currently pcbs point back directly to fwudp. It might
51 * make sense to introduce a per-pcb structure that points to fwudp
52 * and carries additional information, like pre-mapped peer address.
53 */
54struct fwudp {
55 /**
56 * Our poll manager handler.
57 */
58 struct pollmgr_handler pmhdl;
59
60 /**
61 * Forwarding specification.
62 */
63 struct fwspec fwspec;
64
65 /**
66 * XXX: lwip-format copy of destination
67 */
68 ipX_addr_t dst_addr;
69 u16_t dst_port;
70
71 /**
72 * Listening socket.
73 */
74 SOCKET sock;
75
76 /**
77 * Ring-buffer for inbound datagrams.
78 */
79 struct {
80 struct fwudp_dgram *buf;
81 size_t bufsize;
82 volatile size_t vacant;
83 volatile size_t unsent;
84 } inbuf;
85
86 struct tcpip_msg msg_send;
87 struct tcpip_msg msg_delete;
88
89 struct fwudp *next;
90};
91
92
93struct fwudp *fwudp_create(struct fwspec *);
94
95/* poll manager callback for fwudp socket */
96static int fwudp_pmgr_pump(struct pollmgr_handler *, SOCKET, int);
97
98/* lwip thread callbacks called via proxy_lwip_post() */
99static void fwudp_pcb_send(void *);
100static void fwudp_pcb_delete(void *);
101
102static void fwudp_pcb_recv(void *, struct udp_pcb *, struct pbuf *, ip_addr_t *, u16_t);
103static void fwudp_pcb_forward_outbound(struct fwudp *, struct udp_pcb *, struct pbuf *);
104
105
106/**
107 * Linked list of active fwtcp forwarders.
108 */
109struct fwudp *fwudp_list = NULL;
110
111
112void
113fwudp_init(void)
114{
115 return;
116}
117
118
119void
120fwudp_add(struct fwspec *fwspec)
121{
122 struct fwudp *fwudp;
123
124 fwudp = fwudp_create(fwspec);
125 if (fwudp == NULL) {
126 DPRINTF0(("%s: failed to add rule for UDP ...\n", __func__));
127 return;
128 }
129
130 DPRINTF0(("%s\n", __func__));
131 /* fwudp_create has put fwudp on the linked list */
132}
133
134
135void
136fwudp_del(struct fwspec *fwspec)
137{
138 struct fwudp *fwudp;
139 struct fwudp **pprev;
140
141 for (pprev = &fwudp_list; (fwudp = *pprev) != NULL; pprev = &fwudp->next) {
142 if (fwspec_equal(&fwudp->fwspec, fwspec)) {
143 *pprev = fwudp->next;
144 fwudp->next = NULL;
145 break;
146 }
147 }
148
149 if (fwudp == NULL) {
150 DPRINTF0(("%s: not found\n", __func__));
151 return;
152 }
153
154 DPRINTF0(("%s\n", __func__));
155
156 pollmgr_del_slot(fwudp->pmhdl.slot);
157 fwudp->pmhdl.slot = -1;
158
159 /* let pending msg_send be processed before we delete fwudp */
160 proxy_lwip_post(&fwudp->msg_delete);
161}
162
163
164struct fwudp *
165fwudp_create(struct fwspec *fwspec)
166{
167 struct fwudp *fwudp;
168 SOCKET sock;
169 int status;
170
171 sock = proxy_bound_socket(fwspec->sdom, fwspec->stype, &fwspec->src.sa);
172 if (sock == INVALID_SOCKET) {
173 perror("socket");
174 return NULL;
175 }
176
177 fwudp = (struct fwudp *)malloc(sizeof(*fwudp));
178 if (fwudp == NULL) {
179 closesocket(sock);
180 return NULL;
181 }
182
183 fwudp->pmhdl.callback = fwudp_pmgr_pump;
184 fwudp->pmhdl.data = (void *)fwudp;
185 fwudp->pmhdl.slot = -1;
186
187 fwudp->sock = sock;
188 fwudp->fwspec = *fwspec; /* struct copy */
189
190 /* XXX */
191 if (fwspec->sdom == PF_INET) {
192 struct sockaddr_in *dst4 = &fwspec->dst.sin;
193 memcpy(&fwudp->dst_addr.ip4, &dst4->sin_addr, sizeof(ip_addr_t));
194 fwudp->dst_port = htons(dst4->sin_port);
195 }
196 else { /* PF_INET6 */
197 struct sockaddr_in6 *dst6 = &fwspec->dst.sin6;
198 memcpy(&fwudp->dst_addr.ip6, &dst6->sin6_addr, sizeof(ip6_addr_t));
199 fwudp->dst_port = htons(dst6->sin6_port);
200 }
201
202 fwudp->inbuf.bufsize = 256; /* elements */
203 fwudp->inbuf.buf
204 = (struct fwudp_dgram *)calloc(fwudp->inbuf.bufsize,
205 sizeof(struct fwudp_dgram));
206 if (fwudp->inbuf.buf == NULL) {
207 closesocket(sock);
208 free(fwudp);
209 return (NULL);
210 }
211 fwudp->inbuf.vacant = 0;
212 fwudp->inbuf.unsent = 0;
213
214#define CALLBACK_MSG(MSG, FUNC) \
215 do { \
216 fwudp->MSG.type = TCPIP_MSG_CALLBACK_STATIC; \
217 fwudp->MSG.sem = NULL; \
218 fwudp->MSG.msg.cb.function = FUNC; \
219 fwudp->MSG.msg.cb.ctx = (void *)fwudp; \
220 } while (0)
221
222 CALLBACK_MSG(msg_send, fwudp_pcb_send);
223 CALLBACK_MSG(msg_delete, fwudp_pcb_delete);
224
225#undef CALLBACK_MSG
226
227 status = pollmgr_add(&fwudp->pmhdl, fwudp->sock, POLLIN);
228 if (status < 0) {
229 closesocket(sock);
230 free(fwudp->inbuf.buf);
231 free(fwudp);
232 return NULL;
233 }
234
235 fwudp->next = fwudp_list;
236 fwudp_list = fwudp;
237
238 return fwudp;
239}
240
241
242/**
243 * Poll manager callaback for fwudp::sock
244 */
245int
246fwudp_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents)
247{
248 struct fwudp *fwudp;
249 struct sockaddr_storage ss;
250 socklen_t sslen = sizeof(ss);
251 size_t beg, lim;
252 struct fwudp_dgram *dgram;
253 struct pbuf *p;
254 ssize_t nread;
255 int status;
256 err_t error;
257
258 fwudp = (struct fwudp *)handler->data;
259
260 LWIP_ASSERT1(fwudp != NULL);
261 LWIP_ASSERT1(fd == fwudp->sock);
262 LWIP_ASSERT1(revents == POLLIN);
263 LWIP_UNUSED_ARG(fd);
264 LWIP_UNUSED_ARG(revents);
265
266 nread = recvfrom(fwudp->sock, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0,
267 (struct sockaddr *)&ss, &sslen);
268 if (nread < 0) {
269 perror(__func__);
270 return POLLIN;
271 }
272
273 /* Check that ring buffer is not full */
274 lim = fwudp->inbuf.unsent;
275 if (lim == 0) {
276 lim = fwudp->inbuf.bufsize - 1; /* guard slot at the end */
277 }
278 else {
279 --lim;
280 }
281
282 beg = fwudp->inbuf.vacant;
283 if (beg == lim) { /* no vacant slot */
284 return POLLIN;
285 }
286
287
288 dgram = &fwudp->inbuf.buf[beg];
289
290
291 status = fwany_ipX_addr_set_src(&dgram->src_addr, (struct sockaddr *)&ss);
292 if (status == PXREMAP_FAILED) {
293 return POLLIN;
294 }
295
296 if (ss.ss_family == AF_INET) {
297 const struct sockaddr_in *peer4 = (const struct sockaddr_in *)&ss;
298 dgram->src_port = htons(peer4->sin_port);
299 }
300 else { /* PF_INET6 */
301 const struct sockaddr_in6 *peer6 = (const struct sockaddr_in6 *)&ss;
302 dgram->src_port = htons(peer6->sin6_port);
303 }
304
305 p = pbuf_alloc(PBUF_RAW, nread, PBUF_RAM);
306 if (p == NULL) {
307 DPRINTF(("%s: pbuf_alloc(%d) failed\n", __func__, (int)nread));
308 return POLLIN;
309 }
310
311 error = pbuf_take(p, pollmgr_udpbuf, nread);
312 if (error != ERR_OK) {
313 DPRINTF(("%s: pbuf_take(%d) failed\n", __func__, (int)nread));
314 pbuf_free(p);
315 return POLLIN;
316 }
317
318 dgram->p = p;
319
320 ++beg;
321 if (beg == fwudp->inbuf.bufsize) {
322 beg = 0;
323 }
324 fwudp->inbuf.vacant = beg;
325
326 proxy_lwip_post(&fwudp->msg_send);
327
328 return POLLIN;
329}
330
331
332/**
333 * Lwip thread callback invoked via fwudp::msg_send
334 */
335void
336fwudp_pcb_send(void *arg)
337{
338 struct fwudp *fwudp = (struct fwudp *)arg;
339 struct fwudp_dgram dgram;
340 struct udp_pcb *pcb;
341 struct udp_pcb **pprev;
342 int isv6;
343 size_t idx;
344
345 idx = fwudp->inbuf.unsent;
346
347 if (idx == fwudp->inbuf.vacant) {
348 /* empty buffer - shouldn't happen! */
349 DPRINTF(("%s: ring buffer empty!\n", __func__));
350 return;
351 }
352
353 dgram = fwudp->inbuf.buf[idx]; /* struct copy */
354#if 1 /* valgrind hint */
355 fwudp->inbuf.buf[idx].p = NULL;
356#endif
357 if (++idx == fwudp->inbuf.bufsize) {
358 idx = 0;
359 }
360 fwudp->inbuf.unsent = idx;
361
362 /* XXX: this is *STUPID* */
363 isv6 = (fwudp->fwspec.sdom == PF_INET6);
364 pprev = &udp_proxy_pcbs;
365 for (pcb = udp_proxy_pcbs; pcb != NULL; pcb = pcb->next) {
366 if (PCB_ISIPV6(pcb) == isv6
367 && pcb->remote_port == fwudp->dst_port
368 && ipX_addr_cmp(isv6, &fwudp->dst_addr, &pcb->remote_ip)
369 && pcb->local_port == dgram.src_port
370 && ipX_addr_cmp(isv6, &dgram.src_addr, &pcb->local_ip))
371 {
372 break;
373 }
374 else {
375 pprev = &pcb->next;
376 }
377 }
378
379 if (pcb != NULL) {
380 *pprev = pcb->next;
381 pcb->next = udp_proxy_pcbs;
382 udp_proxy_pcbs = pcb;
383
384 /*
385 * XXX: check that its ours and not accidentally created by
386 * outbound traffic.
387 *
388 * ???: Otherwise? Expire it and set pcb = NULL; to create a
389 * new one below?
390 */
391 }
392
393 if (pcb == NULL) {
394 pcb = udp_new();
395 if (pcb == NULL) {
396 goto out;
397 }
398
399 ip_set_v6(pcb, isv6);
400
401 /* equivalent of udp_bind */
402 ipX_addr_set(isv6, &pcb->local_ip, &dgram.src_addr);
403 pcb->local_port = dgram.src_port;
404
405 /* equivalent to udp_connect */
406 ipX_addr_set(isv6, &pcb->remote_ip, &fwudp->dst_addr);
407 pcb->remote_port = fwudp->dst_port;
408 pcb->flags |= UDP_FLAGS_CONNECTED;
409
410 udp_recv(pcb, fwudp_pcb_recv, fwudp);
411
412 pcb->next = udp_proxy_pcbs;
413 udp_proxy_pcbs = pcb;
414 udp_proxy_timer_needed();
415 }
416
417 udp_send(pcb, dgram.p);
418
419 out:
420 pbuf_free(dgram.p);
421}
422
423
424/**
425 * udp_recv() callback.
426 */
427void
428fwudp_pcb_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
429 ip_addr_t *addr, u16_t port)
430{
431 struct fwudp *fwudp = (struct fwudp *)arg;
432
433 LWIP_UNUSED_ARG(addr);
434 LWIP_UNUSED_ARG(port);
435
436 LWIP_ASSERT1(fwudp != NULL);
437
438 if (p == NULL) {
439 DPRINTF(("%s: pcb %p (fwudp %p); sock %d: expired\n",
440 __func__, (void *)pcb, (void *)fwudp, fwudp->sock));
441 /* NB: fwudp is "global" and not deleted */
442 /* XXX: TODO: delete local reference when we will keep one */
443 udp_remove(pcb);
444 return;
445 }
446 else {
447 fwudp_pcb_forward_outbound(fwudp, pcb, p);
448 }
449}
450
451
452/*
453 * XXX: This is pxudp_pcb_forward_outbound modulo:
454 * - s/pxudp/fwudp/g
455 * - addr/port (unused in either) dropped
456 * - destination is specified since host socket is not connected
457 */
458static void
459fwudp_pcb_forward_outbound(struct fwudp *fwudp, struct udp_pcb *pcb,
460 struct pbuf *p)
461{
462 union {
463 struct sockaddr_in sin;
464 struct sockaddr_in6 sin6;
465 } peer;
466 socklen_t namelen;
467
468 memset(&peer, 0, sizeof(peer)); /* XXX: shut up valgrind */
469
470 if (fwudp->fwspec.sdom == PF_INET) {
471 peer.sin.sin_family = AF_INET;
472#if HAVE_SA_LEN
473 peer.sin.sin_len =
474#endif
475 namelen = sizeof(peer.sin);
476 pxremap_outbound_ip4((ip_addr_t *)&peer.sin.sin_addr, &pcb->local_ip.ip4);
477 peer.sin.sin_port = htons(pcb->local_port);
478 }
479 else {
480 peer.sin6.sin6_family = AF_INET6;
481#if HAVE_SA_LEN
482 peer.sin6.sin6_len =
483#endif
484 namelen = sizeof(peer.sin6);
485
486 pxremap_outbound_ip6((ip6_addr_t *)&peer.sin6.sin6_addr, &pcb->local_ip.ip6);
487 peer.sin6.sin6_port = htons(pcb->local_port);
488 }
489
490 proxy_sendto(fwudp->sock, p, &peer, namelen);
491 pbuf_free(p);
492}
493
494
495/**
496 * Lwip thread callback invoked via fwudp::msg_delete
497 */
498static void
499fwudp_pcb_delete(void *arg)
500{
501 struct fwudp *fwudp = (struct fwudp *)arg;
502 struct udp_pcb *pcb;
503 struct udp_pcb **pprev;
504
505 LWIP_ASSERT1(fwudp->inbuf.unsent == fwudp->inbuf.vacant);
506
507 pprev = &udp_proxy_pcbs;
508 pcb = udp_proxy_pcbs;
509 while (pcb != NULL) {
510 if (pcb->recv_arg != fwudp) {
511 pprev = &pcb->next;
512 pcb = pcb->next;
513 }
514 else {
515 struct udp_pcb *dead = pcb;
516 pcb = pcb->next;
517 *pprev = pcb;
518 memp_free(MEMP_UDP_PCB, dead);
519 }
520 }
521
522 closesocket(fwudp->sock);
523 free(fwudp->inbuf.buf);
524 free(fwudp);
525}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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