VirtualBox

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

Last change on this file since 78071 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.4 KB
Line 
1/* $Id: portfwd.c 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * NAT Network - port-forwarding rules.
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 "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 DPRINTF0(("%s: failed to allocate message\n", __func__));
91 return -1;
92 }
93
94 msg->fwspec = fwspec;
95 msg->add = add;
96
97 return portfwd_chan_send(msg);
98}
99
100
101int
102portfwd_rule_add(struct fwspec *fwspec)
103{
104 return portfwd_rule_add_del(fwspec, 1);
105}
106
107
108int
109portfwd_rule_del(struct fwspec *fwspec)
110{
111 return portfwd_rule_add_del(fwspec, 0);
112}
113
114
115/**
116 * POLLMGR_CHAN_PORTFWD handler.
117 */
118static int
119portfwd_pmgr_chan(struct pollmgr_handler *handler, SOCKET fd, int revents)
120{
121 void *ptr = pollmgr_chan_recv_ptr(handler, fd, revents);
122 struct portfwd_msg *msg = (struct portfwd_msg *)ptr;
123
124 if (msg->fwspec->stype == SOCK_STREAM) {
125 if (msg->add) {
126 fwtcp_add(msg->fwspec);
127 }
128 else {
129 fwtcp_del(msg->fwspec);
130 }
131 }
132 else { /* SOCK_DGRAM */
133 if (msg->add) {
134 fwudp_add(msg->fwspec);
135 }
136 else {
137 fwudp_del(msg->fwspec);
138 }
139 }
140
141 free(msg->fwspec);
142 free(msg);
143
144 return POLLIN;
145}
146
147
148int
149fwspec_set(struct fwspec *fwspec, int sdom, int stype,
150 const char *src_addr_str, uint16_t src_port,
151 const char *dst_addr_str, uint16_t dst_port)
152{
153 struct addrinfo hints;
154 struct addrinfo *ai;
155 int status;
156
157 LWIP_ASSERT1(sdom == PF_INET || sdom == PF_INET6);
158 LWIP_ASSERT1(stype == SOCK_STREAM || stype == SOCK_DGRAM);
159
160 fwspec->sdom = sdom;
161 fwspec->stype = stype;
162
163 memset(&hints, 0, sizeof(hints));
164 hints.ai_family = (sdom == PF_INET) ? AF_INET : AF_INET6;
165 hints.ai_socktype = stype;
166 hints.ai_flags = AI_NUMERICHOST;
167
168 status = getaddrinfo(src_addr_str, NULL, &hints, &ai);
169 if (status != 0) {
170 LogRel(("\"%s\": %s\n", src_addr_str, gai_strerror(status)));
171 return -1;
172 }
173 LWIP_ASSERT1(ai != NULL);
174 LWIP_ASSERT1(ai->ai_addrlen <= sizeof(fwspec->src));
175 memcpy(&fwspec->src, ai->ai_addr, ai->ai_addrlen);
176 freeaddrinfo(ai);
177 ai = NULL;
178
179 status = getaddrinfo(dst_addr_str, NULL, &hints, &ai);
180 if (status != 0) {
181 LogRel(("\"%s\": %s\n", dst_addr_str, gai_strerror(status)));
182 return -1;
183 }
184 LWIP_ASSERT1(ai != NULL);
185 LWIP_ASSERT1(ai->ai_addrlen <= sizeof(fwspec->dst));
186 memcpy(&fwspec->dst, ai->ai_addr, ai->ai_addrlen);
187 freeaddrinfo(ai);
188 ai = NULL;
189
190 if (sdom == PF_INET) {
191 fwspec->src.sin.sin_port = htons(src_port);
192 fwspec->dst.sin.sin_port = htons(dst_port);
193 }
194 else { /* PF_INET6 */
195 fwspec->src.sin6.sin6_port = htons(src_port);
196 fwspec->dst.sin6.sin6_port = htons(dst_port);
197 }
198
199 return 0;
200}
201
202
203int
204fwspec_equal(struct fwspec *a, struct fwspec *b)
205{
206 LWIP_ASSERT1(a != NULL);
207 LWIP_ASSERT1(b != NULL);
208
209 if (a->sdom != b->sdom || a->stype != b->stype) {
210 return 0;
211 }
212
213 if (a->sdom == PF_INET) {
214 return a->src.sin.sin_port == b->src.sin.sin_port
215 && a->dst.sin.sin_port == b->dst.sin.sin_port
216 && a->src.sin.sin_addr.s_addr == b->src.sin.sin_addr.s_addr
217 && a->dst.sin.sin_addr.s_addr == b->dst.sin.sin_addr.s_addr;
218 }
219 else { /* PF_INET6 */
220 return a->src.sin6.sin6_port == b->src.sin6.sin6_port
221 && a->dst.sin6.sin6_port == b->dst.sin6.sin6_port
222 && IN6_ARE_ADDR_EQUAL(&a->src.sin6.sin6_addr, &b->src.sin6.sin6_addr)
223 && IN6_ARE_ADDR_EQUAL(&a->dst.sin6.sin6_addr, &b->dst.sin6.sin6_addr);
224 }
225}
226
227
228/**
229 * Set fwdsrc to the IP address of the peer.
230 *
231 * For port-forwarded connections originating from hosts loopback the
232 * source address is set to the address of one of lwIP interfaces.
233 *
234 * Currently we only have one interface so there's not much logic
235 * here. In the future we might need to additionally consult fwspec
236 * and routing table to determine which netif is used for connections
237 * to the specified guest.
238 */
239int
240fwany_ipX_addr_set_src(ipX_addr_t *fwdsrc, const struct sockaddr *peer)
241{
242 int mapping;
243
244 if (peer->sa_family == AF_INET) {
245 const struct sockaddr_in *peer4 = (const struct sockaddr_in *)peer;
246 ip_addr_t peerip4;
247
248 peerip4.addr = peer4->sin_addr.s_addr;
249 mapping = pxremap_inbound_ip4(&fwdsrc->ip4, &peerip4);
250 }
251 else if (peer->sa_family == AF_INET6) {
252 const struct sockaddr_in6 *peer6 = (const struct sockaddr_in6 *)peer;
253 ip6_addr_t peerip6;
254
255 memcpy(&peerip6, &peer6->sin6_addr, sizeof(ip6_addr_t));
256 mapping = pxremap_inbound_ip6(&fwdsrc->ip6, &peerip6);
257 }
258 else {
259 mapping = PXREMAP_FAILED;
260 }
261
262 return mapping;
263}
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