VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/fwtcp.c@ 77758

Last change on this file since 77758 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 6.9 KB
Line 
1/* $Id: fwtcp.c 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * NAT Network - TCP port-forwarding.
4 */
5
6/*
7 * Copyright (C) 2013-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP LOG_GROUP_NAT_SERVICE
19
20#include "winutils.h"
21#include "proxy.h"
22#include "proxy_pollmgr.h"
23#include "portfwd.h"
24#include "pxtcp.h"
25
26#ifndef RT_OS_WINDOWS
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <arpa/inet.h>
30#include <stdio.h>
31#include <poll.h>
32
33#include <err.h> /* BSD'ism */
34#else
35#include <stdio.h>
36#include "winpoll.h"
37#endif
38
39#include "lwip/opt.h"
40
41#include "lwip/sys.h"
42#include "lwip/tcpip.h"
43
44
45/**
46 */
47struct fwtcp {
48 /**
49 * Our poll manager handler.
50 */
51 struct pollmgr_handler pmhdl;
52
53 /**
54 * Forwarding specification.
55 */
56 struct fwspec fwspec;
57
58 /**
59 * Listening socket.
60 */
61 SOCKET sock;
62
63 /**
64 * Mailbox for new inbound connections.
65 *
66 * XXX: since we have single producer and single consumer we can
67 * use lockless ringbuf like for pxtcp.
68 */
69 sys_mbox_t connmbox;
70
71 struct tcpip_msg msg_connect;
72 struct tcpip_msg msg_delete;
73
74 /**
75 * Linked list entry.
76 */
77 struct fwtcp *next;
78};
79
80
81static struct fwtcp *fwtcp_create(struct fwspec *);
82
83/* poll manager callback for fwtcp listening socket */
84static int fwtcp_pmgr_listen(struct pollmgr_handler *, SOCKET, int);
85
86/* lwip thread callbacks called via proxy_lwip_post() */
87static void fwtcp_pcb_connect(void *);
88static void fwtcp_pcb_delete(void *);
89
90
91/**
92 * Linked list of active fwtcp forwarders.
93 */
94struct fwtcp *fwtcp_list = NULL;
95
96
97void
98fwtcp_init(void)
99{
100 return;
101}
102
103
104void
105fwtcp_add(struct fwspec *fwspec)
106{
107 struct fwtcp *fwtcp;
108
109 fwtcp = fwtcp_create(fwspec);
110 if (fwtcp == NULL) {
111 DPRINTF0(("%s: failed to add rule for TCP ...\n", __func__));
112 return;
113 }
114
115 DPRINTF0(("%s\n", __func__));
116 /* fwtcp_create has put fwtcp on the linked list */
117}
118
119
120void
121fwtcp_del(struct fwspec *fwspec)
122{
123 struct fwtcp *fwtcp;
124 struct fwtcp **pprev;
125
126 for (pprev = &fwtcp_list; (fwtcp = *pprev) != NULL; pprev = &fwtcp->next) {
127 if (fwspec_equal(&fwtcp->fwspec, fwspec)) {
128 *pprev = fwtcp->next;
129 fwtcp->next = NULL;
130 break;
131 }
132 }
133
134 if (fwtcp == NULL) {
135 DPRINTF0(("%s: not found\n", __func__));
136 return;
137 }
138
139 DPRINTF0(("%s\n", __func__));
140
141 pollmgr_del_slot(fwtcp->pmhdl.slot);
142 fwtcp->pmhdl.slot = -1;
143
144 closesocket(fwtcp->sock);
145 fwtcp->sock = INVALID_SOCKET;
146
147 /* let pending msg_connect be processed before we delete fwtcp */
148 proxy_lwip_post(&fwtcp->msg_delete);
149}
150
151
152struct fwtcp *
153fwtcp_create(struct fwspec *fwspec)
154{
155 struct fwtcp *fwtcp;
156 SOCKET lsock;
157 int status;
158 err_t error;
159
160 lsock = proxy_bound_socket(fwspec->sdom, fwspec->stype, &fwspec->src.sa);
161 if (lsock == INVALID_SOCKET) {
162 return NULL;
163 }
164
165 fwtcp = (struct fwtcp *)malloc(sizeof(*fwtcp));
166 if (fwtcp == NULL) {
167 closesocket(lsock);
168 return NULL;
169 }
170
171 fwtcp->pmhdl.callback = fwtcp_pmgr_listen;
172 fwtcp->pmhdl.data = (void *)fwtcp;
173 fwtcp->pmhdl.slot = -1;
174
175 fwtcp->sock = lsock;
176 fwtcp->fwspec = *fwspec; /* struct copy */
177
178 error = sys_mbox_new(&fwtcp->connmbox, 16);
179 if (error != ERR_OK) {
180 closesocket(lsock);
181 free(fwtcp);
182 return (NULL);
183 }
184
185#define CALLBACK_MSG(MSG, FUNC) \
186 do { \
187 fwtcp->MSG.type = TCPIP_MSG_CALLBACK_STATIC; \
188 fwtcp->MSG.sem = NULL; \
189 fwtcp->MSG.msg.cb.function = FUNC; \
190 fwtcp->MSG.msg.cb.ctx = (void *)fwtcp; \
191 } while (0)
192
193 CALLBACK_MSG(msg_connect, fwtcp_pcb_connect);
194 CALLBACK_MSG(msg_delete, fwtcp_pcb_delete);
195
196#undef CALLBACK_MSG
197
198 status = pollmgr_add(&fwtcp->pmhdl, fwtcp->sock, POLLIN);
199 if (status < 0) {
200 sys_mbox_free(&fwtcp->connmbox);
201 closesocket(lsock);
202 free(fwtcp);
203 return NULL;
204 }
205
206 fwtcp->next = fwtcp_list;
207 fwtcp_list = fwtcp;
208
209 return fwtcp;
210}
211
212
213int
214fwtcp_pmgr_listen(struct pollmgr_handler *handler, SOCKET fd, int revents)
215{
216 struct fwtcp *fwtcp;
217 struct sockaddr_storage ss;
218 socklen_t sslen;
219 struct pxtcp *pxtcp;
220 SOCKET newsock;
221 int status;
222 err_t error;
223
224 fwtcp = (struct fwtcp *)handler->data;
225 pxtcp = NULL;
226
227 LWIP_ASSERT1(fwtcp != NULL);
228 LWIP_ASSERT1(fd == fwtcp->sock);
229 LWIP_ASSERT1(revents == POLLIN);
230 LWIP_UNUSED_ARG(fd);
231 LWIP_UNUSED_ARG(revents);
232
233 LWIP_ASSERT1(sys_mbox_valid(&fwtcp->connmbox));
234
235 sslen = sizeof(ss);
236 newsock = accept(fwtcp->sock, (struct sockaddr *)&ss, &sslen);
237 if (newsock == INVALID_SOCKET) {
238 return POLLIN;
239 }
240
241
242 if (ss.ss_family == PF_INET) {
243 struct sockaddr_in *peer4 = (struct sockaddr_in *)&ss;
244 RT_NOREF(peer4);
245 DPRINTF(("<--- TCP %RTnaipv4:%d\n",
246 peer4->sin_addr.s_addr, ntohs(peer4->sin_port)));
247 }
248 else { /* PF_INET6 */
249 struct sockaddr_in6 *peer6 = (struct sockaddr_in6 *)&ss;
250 RT_NOREF(peer6);
251 DPRINTF(("<--- TCP %RTnaipv6:%d\n",
252 &peer6->sin6_addr, ntohs(peer6->sin6_port)));
253 }
254
255 pxtcp = pxtcp_create_forwarded(newsock);
256 if (pxtcp == NULL) {
257 proxy_reset_socket(newsock);
258 return POLLIN;
259 }
260
261 status = pxtcp_pmgr_add(pxtcp);
262 if (status < 0) {
263 pxtcp_cancel_forwarded(pxtcp);
264 return POLLIN;
265 }
266
267 error = sys_mbox_trypost(&fwtcp->connmbox, (void *)pxtcp);
268 if (error != ERR_OK) {
269 pxtcp_pmgr_del(pxtcp);
270 pxtcp_cancel_forwarded(pxtcp);
271 return POLLIN;
272 }
273
274 proxy_lwip_post(&fwtcp->msg_connect);
275 return POLLIN;
276}
277
278
279void
280fwtcp_pcb_connect(void *arg)
281{
282 struct fwtcp *fwtcp = (struct fwtcp *)arg;
283 struct pxtcp *pxtcp;
284 u32_t timo;
285
286 if (!sys_mbox_valid(&fwtcp->connmbox)) {
287 return;
288 }
289
290 pxtcp = NULL;
291 timo = sys_mbox_tryfetch(&fwtcp->connmbox, (void **)&pxtcp);
292 if (timo == SYS_MBOX_EMPTY) {
293 return;
294 }
295
296 LWIP_ASSERT1(pxtcp != NULL);
297
298 /* hand off to pxtcp */
299 pxtcp_pcb_connect(pxtcp, &fwtcp->fwspec);
300}
301
302
303static void
304fwtcp_pcb_delete(void *arg)
305{
306 struct fwtcp *fwtcp = (struct fwtcp *)arg;
307 void *data;
308 u32_t timo;
309
310 timo = sys_mbox_tryfetch(&fwtcp->connmbox, &data);
311 LWIP_ASSERT1(timo == SYS_MBOX_EMPTY);
312 LWIP_UNUSED_ARG(timo); /* only in assert */
313
314 sys_mbox_free(&fwtcp->connmbox);
315 free(fwtcp);
316}
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