VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/portfwd.c@ 49022

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

VBoxNetNAT/Win: removes inet_pton's Vista limitation, instead WSAStringToAddressA (minimum supported version is Win2k) is used. (tested for IPv4, in documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/ms742214%28v=vs.85%29.aspx) hasn't mentioned any IPv6 limitations)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 7.6 KB
Line 
1/* -*- indent-tabs-mode: nil; -*- */
2#include "winutils.h"
3#include "portfwd.h"
4
5#ifndef RT_OS_WINDOWS
6#include <arpa/inet.h>
7#include <poll.h>
8#else
9# include "winpoll.h"
10#endif
11#include <stdio.h>
12#include <string.h>
13
14#include "proxy.h"
15#include "proxy_pollmgr.h"
16#include "pxremap.h"
17
18#include "lwip/netif.h"
19
20
21struct portfwd_msg {
22 struct fwspec *fwspec;
23 int add;
24};
25
26
27static int portfwd_chan_send(struct portfwd_msg *);
28static int portfwd_rule_add_del(struct fwspec *, SOCKET);
29static int portfwd_pmgr_chan(struct pollmgr_handler *, SOCKET, int);
30
31
32static struct pollmgr_handler portfwd_pmgr_chan_hdl;
33
34
35void
36portfwd_init(void)
37{
38 portfwd_pmgr_chan_hdl.callback = portfwd_pmgr_chan;
39 portfwd_pmgr_chan_hdl.data = NULL;
40 portfwd_pmgr_chan_hdl.slot = -1;
41 pollmgr_add_chan(POLLMGR_CHAN_PORTFWD, &portfwd_pmgr_chan_hdl);
42
43 /* add preconfigured forwarders */
44 fwtcp_init();
45 fwudp_init();
46}
47
48
49static int
50portfwd_chan_send(struct portfwd_msg *msg)
51{
52 ssize_t nsent;
53
54 nsent = pollmgr_chan_send(POLLMGR_CHAN_PORTFWD, &msg, sizeof(msg));
55 if (nsent < 0) {
56 free(msg);
57 return -1;
58 }
59
60 return 0;
61}
62
63
64static int
65portfwd_rule_add_del(struct fwspec *fwspec, int add)
66{
67 struct portfwd_msg *msg;
68
69 msg = (struct portfwd_msg *)malloc(sizeof(*msg));
70 if (msg == NULL) {
71 return -1;
72 }
73
74 msg->fwspec = fwspec;
75 msg->add = add;
76
77 return portfwd_chan_send(msg);
78}
79
80
81int
82portfwd_rule_add(struct fwspec *fwspec)
83{
84 return portfwd_rule_add_del(fwspec, 1);
85}
86
87
88int
89portfwd_rule_del(struct fwspec *fwspec)
90{
91 return portfwd_rule_add_del(fwspec, 0);
92}
93
94
95/**
96 * POLLMGR_CHAN_PORTFWD handler.
97 */
98static int
99portfwd_pmgr_chan(struct pollmgr_handler *handler, SOCKET fd, int revents)
100{
101 void *ptr = pollmgr_chan_recv_ptr(handler, fd, revents);
102 struct portfwd_msg *msg = (struct portfwd_msg *)ptr;
103
104 if (msg->fwspec->stype == SOCK_STREAM) {
105 if (msg->add) {
106 fwtcp_add(msg->fwspec);
107 }
108 else {
109 fwtcp_del(msg->fwspec);
110 }
111 }
112 else { /* SOCK_DGRAM */
113 if (msg->add) {
114 fwudp_add(msg->fwspec);
115 }
116 else {
117 fwudp_del(msg->fwspec);
118 }
119 }
120
121 free(msg->fwspec);
122 free(msg);
123
124 return POLLIN;
125}
126
127
128
129#ifndef RT_OS_WINDOWS
130int
131fwspec_set(struct fwspec *fwspec, int sdom, int stype,
132 const char *src_addr_str, uint16_t src_port,
133 const char *dst_addr_str, uint16_t dst_port)
134{
135 int status;
136 int saf;
137 void *src_addr, *dst_addr;
138
139 LWIP_ASSERT1(sdom == PF_INET || sdom == PF_INET6);
140 LWIP_ASSERT1(stype == SOCK_STREAM || stype == SOCK_DGRAM);
141
142 fwspec->sdom = sdom;
143 fwspec->stype = stype;
144
145 if (sdom == PF_INET) {
146 struct sockaddr_in *src = &fwspec->src.sin;
147 struct sockaddr_in *dst = &fwspec->dst.sin;
148
149 saf = AF_INET;
150
151 src->sin_family = saf;
152#if HAVE_SA_LEN
153 src->sin_len = sizeof(*src);
154#endif
155 src->sin_port = htons(src_port);
156 src_addr = &src->sin_addr;
157
158 dst->sin_family = saf;
159#if HAVE_SA_LEN
160 dst->sin_len = sizeof(*dst);
161#endif
162 dst->sin_port = htons(dst_port);
163 dst_addr = &dst->sin_addr;
164 }
165 else { /* PF_INET6 */
166 struct sockaddr_in6 *src = &fwspec->src.sin6;
167 struct sockaddr_in6 *dst = &fwspec->dst.sin6;
168
169 saf = AF_INET6;
170
171 src->sin6_family = saf;
172#if HAVE_SA_LEN
173 src->sin6_len = sizeof(*src);
174#endif
175 src->sin6_port = htons(src_port);
176 src_addr = &src->sin6_addr;
177
178 dst->sin6_family = saf;
179#if HAVE_SA_LEN
180 dst->sin6_len = sizeof(*dst);
181#endif
182 dst->sin6_port = htons(dst_port);
183 dst_addr = &dst->sin6_addr;
184 }
185
186 status = inet_pton(saf, src_addr_str, src_addr);
187 LWIP_ASSERT1(status >= 0);
188 if (status == 0) {
189 DPRINTF(("bad address: %s\n", src_addr_str));
190 return -1;
191 }
192
193 status = inet_pton(saf, dst_addr_str, dst_addr);
194 LWIP_ASSERT1(status >= 0);
195 if (status == 0) {
196 DPRINTF(("bad address: %s\n", dst_addr_str));
197 return -1;
198 }
199
200 return 0;
201}
202#else /* RT_OS_WINDOWS */
203/**
204 * Windows only provides inet_pton() since Vista, but XP already has
205 * WSAStringToAddressA() that does what we want (NB: its AddressString
206 * argument is not declared const).
207 */
208int
209fwspec_set(struct fwspec *fwspec, int sdom, int stype,
210 const char *src_addr_str, uint16_t src_port,
211 const char *dst_addr_str, uint16_t dst_port)
212{
213 int saf;
214 int socklen;
215 int status;
216
217 LWIP_ASSERT1(sdom == PF_INET || sdom == PF_INET6);
218 LWIP_ASSERT1(stype == SOCK_STREAM || stype == SOCK_DGRAM);
219
220 fwspec->sdom = sdom;
221 fwspec->stype = stype;
222
223 saf = (sdom == PF_INET) ? AF_INET : AF_INET6;
224
225 socklen = sizeof(fwspec->src);
226 fwspec->src.sa.sa_family = saf; /* see "Remarks" WSAStringToAddress */
227 status = WSAStringToAddressA((char *)src_addr_str, saf, NULL,
228 &fwspec->src.sa, &socklen);
229 if (status == SOCKET_ERROR) {
230 int error = WSAGetLastError();
231 return -1;
232 }
233
234 if (fwspec->src.sa.sa_family != saf) {
235 return -1;
236 }
237
238 fwspec->dst.sa.sa_family = saf;
239 socklen = sizeof(fwspec->dst);
240 status = WSAStringToAddressA((char *)dst_addr_str, saf, NULL,
241 &fwspec->dst.sa, &socklen);
242 if (status == SOCKET_ERROR) {
243 int error = WSAGetLastError();
244 return -1;
245 }
246 if (fwspec->dst.sa.sa_family != saf) {
247 return -1;
248 }
249
250 if (sdom == PF_INET) {
251 fwspec->src.sin.sin_port = htons(src_port);
252 fwspec->dst.sin.sin_port = htons(dst_port);
253 }
254 else { /* PF_INET6 */
255 fwspec->src.sin6.sin6_port = htons(src_port);
256 fwspec->dst.sin6.sin6_port = htons(dst_port);
257 }
258
259 return 0;
260}
261#endif /* RT_OS_WINDOWS */
262
263
264int
265fwspec_equal(struct fwspec *a, struct fwspec *b)
266{
267 LWIP_ASSERT1(a != NULL);
268 LWIP_ASSERT1(b != NULL);
269
270 if (a->sdom != b->sdom || a->stype != b->stype) {
271 return 0;
272 }
273
274 if (a->sdom == PF_INET) {
275 return a->src.sin.sin_port == b->src.sin.sin_port
276 && a->dst.sin.sin_port == b->dst.sin.sin_port
277 && a->src.sin.sin_addr.s_addr == b->src.sin.sin_addr.s_addr
278 && a->dst.sin.sin_addr.s_addr == b->dst.sin.sin_addr.s_addr;
279 }
280 else { /* PF_INET6 */
281 return a->src.sin6.sin6_port == b->src.sin6.sin6_port
282 && a->dst.sin6.sin6_port == b->dst.sin6.sin6_port
283 && IN6_ARE_ADDR_EQUAL(&a->src.sin6.sin6_addr, &b->src.sin6.sin6_addr)
284 && IN6_ARE_ADDR_EQUAL(&a->dst.sin6.sin6_addr, &b->dst.sin6.sin6_addr);
285 }
286}
287
288
289/**
290 * Set fwdsrc to the IP address of the peer.
291 *
292 * For port-forwarded connections originating from hosts loopback the
293 * source address is set to the address of one of lwIP interfaces.
294 *
295 * Currently we only have one interface so there's not much logic
296 * here. In the future we might need to additionally consult fwspec
297 * and routing table to determine which netif is used for connections
298 * to the specified guest.
299 */
300int
301fwany_ipX_addr_set_src(ipX_addr_t *fwdsrc, const struct sockaddr *peer)
302{
303 int mapping;
304
305 if (peer->sa_family == AF_INET) {
306 const struct sockaddr_in *peer4 = (const struct sockaddr_in *)peer;
307 ip_addr_t peerip4;
308
309 peerip4.addr = peer4->sin_addr.s_addr;
310 mapping = pxremap_inbound_ip4(&fwdsrc->ip4, &peerip4);
311 }
312 else if (peer->sa_family == AF_INET6) {
313 const struct sockaddr_in6 *peer6 = (const struct sockaddr_in6 *)peer;
314 ip6_addr_t peerip6;
315
316 memcpy(&peerip6, &peer6->sin6_addr, sizeof(ip6_addr_t));
317 mapping = pxremap_inbound_ip6(&fwdsrc->ip6, &peerip6);
318 }
319 else {
320 mapping = PXREMAP_FAILED;
321 }
322
323 return mapping;
324}
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