VirtualBox

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

Last change on this file since 67954 was 62481, checked in by vboxsync, 8 years ago

(C) 2016

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