VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/pxremap.c

Last change on this file 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: 8.8 KB
Line 
1/* $Id: pxremap.c 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * NAT Network - Loopback remapping.
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/*
29 * This file contains functions pertinent to magic address remapping.
30 *
31 * We want to expose host's loopback interfaces to the guest by
32 * mapping them to the addresses from the same prefix/subnet, so if,
33 * for example proxy interface is 10.0.2.1, we redirect traffic to
34 * 10.0.2.2 to host's 127.0.0.1 loopback. If need be, we may extend
35 * this to provide additional mappings, e.g. 127.0.1.1 loopback
36 * address is used on Ubuntu 12.10+ for NetworkManager's dnsmasq.
37 *
38 * Ditto for IPv6, except that IPv6 only has one loopback address.
39 */
40#define LOG_GROUP LOG_GROUP_NAT_SERVICE
41
42#include "winutils.h"
43#include "pxremap.h"
44#include "proxy.h"
45
46#include "lwip/netif.h"
47#include "netif/etharp.h" /* proxy arp hook */
48
49#include "lwip/ip4.h" /* IPv4 divert hook */
50#include "lwip/ip6.h" /* IPv6 divert hook */
51
52#include <string.h>
53
54
55/**
56 * Check if "dst" is an IPv4 address that proxy remaps to host's
57 * loopback.
58 */
59static int
60proxy_ip4_is_mapped_loopback(struct netif *netif, const ip_addr_t *dst, ip_addr_t *lo)
61{
62 u32_t off;
63 const struct ip4_lomap *lomap;
64 size_t i;
65
66 LWIP_ASSERT1(dst != NULL);
67
68 if (g_proxy_options->lomap_desc == NULL) {
69 return 0;
70 }
71
72 if (!ip_addr_netcmp(dst, &netif->ip_addr, &netif->netmask)) {
73 return 0;
74 }
75
76 /* XXX: TODO: check netif is a proxying netif! */
77
78 off = ntohl(ip4_addr_get_u32(dst) & ~ip4_addr_get_u32(&netif->netmask));
79 lomap = g_proxy_options->lomap_desc->lomap;
80 for (i = 0; i < g_proxy_options->lomap_desc->num_lomap; ++i) {
81 if (off == lomap[i].off) {
82 if (lo != NULL) {
83 ip_addr_copy(*lo, lomap[i].loaddr);
84 }
85 return 1;
86 }
87 }
88 return 0;
89}
90
91
92#if ARP_PROXY
93/**
94 * Hook function for etharp_arp_input() - returns true to cause proxy
95 * ARP reply to be generated for "dst".
96 */
97int
98pxremap_proxy_arp(struct netif *netif, ip_addr_t *dst)
99{
100 return proxy_ip4_is_mapped_loopback(netif, dst, NULL);
101}
102#endif /* ARP_PROXY */
103
104
105/**
106 * Hook function for ip_forward() - returns true to divert packets to
107 * "dst" to proxy (instead of forwarding them via "netif" or dropping).
108 */
109int
110pxremap_ip4_divert(struct netif *netif, ip_addr_t *dst)
111{
112 return proxy_ip4_is_mapped_loopback(netif, dst, NULL);
113}
114
115
116/**
117 * Mapping from local network to loopback for outbound connections.
118 *
119 * Copy "src" to "dst" with ip_addr_set(dst, src), but if "src" is a
120 * local network address that maps host's loopback address, copy
121 * loopback address to "dst".
122 */
123int
124pxremap_outbound_ip4(ip_addr_t *dst, ip_addr_t *src)
125{
126 struct netif *netif;
127
128 LWIP_ASSERT1(dst != NULL);
129 LWIP_ASSERT1(src != NULL);
130
131 for (netif = netif_list; netif != NULL; netif = netif->next) {
132 if (netif_is_up(netif) /* && this is a proxy netif */) {
133 if (proxy_ip4_is_mapped_loopback(netif, src, dst)) {
134 return PXREMAP_MAPPED;
135 }
136 }
137 }
138
139 /* not remapped, just copy src */
140 ip_addr_set(dst, src);
141 return PXREMAP_ASIS;
142}
143
144
145/**
146 * Mapping from loopback to local network for inbound (port-forwarded)
147 * connections.
148 *
149 * Copy "src" to "dst" with ip_addr_set(dst, src), but if "src" is a
150 * host's loopback address, copy local network address that maps it to
151 * "dst".
152 */
153int
154pxremap_inbound_ip4(ip_addr_t *dst, ip_addr_t *src)
155{
156 struct netif *netif;
157 const struct ip4_lomap *lomap;
158 unsigned int i;
159
160 if (ip4_addr1(src) != IP_LOOPBACKNET) {
161 ip_addr_set(dst, src);
162 return PXREMAP_ASIS;
163 }
164
165 if (g_proxy_options->lomap_desc == NULL) {
166 return PXREMAP_FAILED;
167 }
168
169#if 0 /* ?TODO: with multiple interfaces we need to consider fwspec::dst */
170 netif = ip_route(target);
171 if (netif == NULL) {
172 return PXREMAP_FAILED;
173 }
174#else
175 netif = netif_list;
176 LWIP_ASSERT1(netif != NULL);
177 LWIP_ASSERT1(netif->next == NULL);
178#endif
179
180 lomap = g_proxy_options->lomap_desc->lomap;
181 for (i = 0; i < g_proxy_options->lomap_desc->num_lomap; ++i) {
182 if (ip_addr_cmp(src, &lomap[i].loaddr)) {
183 ip_addr_t net;
184
185 ip_addr_get_network(&net, &netif->ip_addr, &netif->netmask);
186 ip4_addr_set_u32(dst,
187 htonl(ntohl(ip4_addr_get_u32(&net))
188 + lomap[i].off));
189 return PXREMAP_MAPPED;
190 }
191 }
192
193 return PXREMAP_FAILED;
194}
195
196
197static int
198proxy_ip6_is_mapped_loopback(struct netif *netif, ip6_addr_t *dst)
199{
200 int i;
201
202 /* XXX: TODO: check netif is a proxying netif! */
203
204 LWIP_ASSERT1(dst != NULL);
205
206 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
207 if (ip6_addr_ispreferred(netif_ip6_addr_state(netif, i))
208 && ip6_addr_isuniquelocal(netif_ip6_addr(netif, i)))
209 {
210 ip6_addr_t *ifaddr = netif_ip6_addr(netif, i);
211 if (memcmp(dst, ifaddr, sizeof(ip6_addr_t) - 1) == 0
212 && ((IP6_ADDR_BLOCK8(dst) & 0xff)
213 == (IP6_ADDR_BLOCK8(ifaddr) & 0xff) + 1))
214 {
215 return 1;
216 }
217 }
218 }
219
220 return 0;
221}
222
223
224/**
225 * Hook function for nd6_input() - returns true to cause proxy NA
226 * reply to be generated for "dst".
227 */
228int
229pxremap_proxy_na(struct netif *netif, ip6_addr_t *dst)
230{
231 return proxy_ip6_is_mapped_loopback(netif, dst);
232}
233
234
235/**
236 * Hook function for ip6_forward() - returns true to divert packets to
237 * "dst" to proxy (instead of forwarding them via "netif" or dropping).
238 */
239int
240pxremap_ip6_divert(struct netif *netif, ip6_addr_t *dst)
241{
242 return proxy_ip6_is_mapped_loopback(netif, dst);
243}
244
245
246/**
247 * Mapping from local network to loopback for outbound connections.
248 *
249 * Copy "src" to "dst" with ip6_addr_set(dst, src), but if "src" is a
250 * local network address that maps host's loopback address, copy IPv6
251 * loopback address to "dst".
252 */
253int
254pxremap_outbound_ip6(ip6_addr_t *dst, ip6_addr_t *src)
255{
256 struct netif *netif;
257 int i;
258
259 LWIP_ASSERT1(dst != NULL);
260 LWIP_ASSERT1(src != NULL);
261
262 for (netif = netif_list; netif != NULL; netif = netif->next) {
263 if (!netif_is_up(netif) /* || this is not a proxy netif */) {
264 continue;
265 }
266
267 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
268 if (ip6_addr_ispreferred(netif_ip6_addr_state(netif, i))
269 && ip6_addr_isuniquelocal(netif_ip6_addr(netif, i)))
270 {
271 ip6_addr_t *ifaddr = netif_ip6_addr(netif, i);
272 if (memcmp(src, ifaddr, sizeof(ip6_addr_t) - 1) == 0
273 && ((IP6_ADDR_BLOCK8(src) & 0xff)
274 == (IP6_ADDR_BLOCK8(ifaddr) & 0xff) + 1))
275 {
276 ip6_addr_set_loopback(dst);
277 return PXREMAP_MAPPED;
278 }
279 }
280 }
281 }
282
283 /* not remapped, just copy src */
284 ip6_addr_set(dst, src);
285 return PXREMAP_ASIS;
286}
287
288
289/**
290 * Mapping from loopback to local network for inbound (port-forwarded)
291 * connections.
292 *
293 * Copy "src" to "dst" with ip6_addr_set(dst, src), but if "src" is a
294 * host's loopback address, copy local network address that maps it to
295 * "dst".
296 */
297int
298pxremap_inbound_ip6(ip6_addr_t *dst, ip6_addr_t *src)
299{
300 ip6_addr_t loopback;
301 struct netif *netif;
302 int i;
303
304 ip6_addr_set_loopback(&loopback);
305 if (!ip6_addr_cmp(src, &loopback)) {
306 ip6_addr_set(dst, src);
307 return PXREMAP_ASIS;
308 }
309
310#if 0 /* ?TODO: with multiple interfaces we need to consider fwspec::dst */
311 netif = ip6_route_fwd(target);
312 if (netif == NULL) {
313 return PXREMAP_FAILED;
314 }
315#else
316 netif = netif_list;
317 LWIP_ASSERT1(netif != NULL);
318 LWIP_ASSERT1(netif->next == NULL);
319#endif
320
321 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) {
322 ip6_addr_t *ifaddr = netif_ip6_addr(netif, i);
323 if (ip6_addr_ispreferred(netif_ip6_addr_state(netif, i))
324 && ip6_addr_isuniquelocal(ifaddr))
325 {
326 ip6_addr_set(dst, ifaddr);
327 ++((u8_t *)&dst->addr[3])[3];
328 return PXREMAP_MAPPED;
329 }
330 }
331
332 return PXREMAP_FAILED;
333}
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