VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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