VirtualBox

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

Last change on this file since 94068 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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