VirtualBox

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

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

Use getaddrinfo(3) on Unix.

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