VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NetLib/VBoxNetPortForwardString.cpp@ 94687

Last change on this file since 94687 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 Author Date Id Revision
File size: 10.6 KB
Line 
1/* $Id: VBoxNetPortForwardString.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VBoxNetPortForwardString - Routines for managing port-forward strings.
4 */
5
6/*
7 * Copyright (C) 2006-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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#ifndef RT_OS_WINDOWS
23# include <netinet/in.h>
24#else
25# include <iprt/win/winsock2.h>
26# include <Ws2ipdef.h>
27#endif
28
29#include <iprt/cdefs.h>
30#include <iprt/cidr.h>
31#include <iprt/ctype.h>
32#include <iprt/errcore.h>
33#include <iprt/getopt.h>
34#include <iprt/net.h>
35#include <iprt/param.h>
36#include <iprt/path.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39
40#include <VBox/log.h>
41
42#include "VBoxPortForwardString.h"
43
44
45/*********************************************************************************************************************************
46* Defined Constants And Macros *
47*********************************************************************************************************************************/
48#define PF_FIELD_SEPARATOR ':'
49#define PF_ADDRESS_FIELD_STARTS '['
50#define PF_ADDRESS_FIELD_ENDS ']'
51
52#define PF_STR_FIELD_SEPARATOR ":"
53#define PF_STR_ADDRESS_FIELD_STARTS "["
54#define PF_STR_ADDRESS_FIELD_ENDS "]"
55
56
57static int netPfStrAddressParse(char *pszRaw, size_t cchRaw,
58 char *pszAddress, int cbAddress,
59 bool fEmptyAcceptable)
60{
61 size_t cchField = 0;
62
63 AssertPtrReturn(pszRaw, -1);
64 AssertPtrReturn(pszAddress, -1);
65 AssertReturn(pszRaw[0] == PF_ADDRESS_FIELD_STARTS, -1);
66
67 if (pszRaw[0] == PF_ADDRESS_FIELD_STARTS)
68 {
69 /* shift pszRaw to next symbol */
70 pszRaw++;
71 cchRaw--;
72
73
74 /* we shouldn't face with ending here */
75 AssertReturn(cchRaw > 0, VERR_INVALID_PARAMETER);
76
77 char *pszEndOfAddress = RTStrStr(pszRaw, PF_STR_ADDRESS_FIELD_ENDS);
78
79 /* no pair closing sign */
80 AssertPtrReturn(pszEndOfAddress, VERR_INVALID_PARAMETER);
81
82 cchField = pszEndOfAddress - pszRaw;
83
84 /* field should be less then the rest of the string */
85 AssertReturn(cchField < cchRaw, VERR_INVALID_PARAMETER);
86
87 if (cchField != 0)
88 RTStrCopy(pszAddress, RT_MIN(cchField + 1, (size_t)cbAddress), pszRaw);
89 else if (!fEmptyAcceptable)
90 return -1;
91 }
92
93 AssertReturn(pszRaw[cchField] == PF_ADDRESS_FIELD_ENDS, -1);
94
95 return (int)cchField + 2; /* length of the field and closing braces */
96}
97
98
99/**
100 * Parses a port something.
101 *
102 * @returns Offset relative to @a pszRaw of the end of the port field.
103 * -1 on failure.
104 * @param pszRaw The zero terminated string to parse. Points a field
105 * separator.
106 * @param pu16Port Where to store the port number on success.
107 */
108static int netPfStrPortParse(char *pszRaw, uint16_t *pu16Port)
109{
110#if 1
111 AssertPtrReturn(pszRaw, -1);
112 AssertPtrReturn(pu16Port, -1);
113 AssertReturn(pszRaw[0] == PF_FIELD_SEPARATOR, -1);
114
115 char *pszNext = NULL;
116 int rc = RTStrToUInt16Ex(&pszRaw[1], &pszNext, 0, pu16Port);
117 if (rc == VWRN_TRAILING_CHARS)
118 AssertReturn(*pszNext == PF_FIELD_SEPARATOR, -1);
119 else if (rc == VINF_SUCCESS)
120 Assert(*pszNext == '\0');
121 else
122 AssertMsgFailedReturn(("rc=%Rrc\n", rc), -1);
123 if (*pu16Port == 0)
124 return -1;
125 return (int)(pszNext - pszRaw);
126
127#else /* The same code, just a little more verbose: */
128 char *pszEndOfPort = NULL;
129 uint16_t u16Port = 0;
130 int idxRaw = 1; /* we increment pszRaw after checks. */
131 int cbRest = 0;
132 size_t cbPort = 0;
133
134 AssertPtrReturn(pszRaw, -1);
135 AssertPtrReturn(pu16Port, -1);
136 AssertReturn(pszRaw[0] == PF_FIELD_SEPARATOR, -1);
137
138 pszRaw++; /* skip field separator */
139 cchRaw --;
140
141 char *pszEndOfPort = RTStrStr(pszRaw, ":");
142 if (!pszEndOfPort)
143 {
144 cbRest = strlen(pszRaw);
145
146 Assert(cchRaw == cbRest);
147
148 /* XXX: Assumption that if string is too big, it will be reported by
149 * RTStrToUint16.
150 */
151 if (cbRest > 0)
152 {
153 pszEndOfPort = pszRaw + cbRest;
154 cbPort = cbRest;
155 }
156 else
157 return -1;
158 }
159 else
160 cbPort = pszEndOfPort - pszRaw;
161
162
163 idxRaw += cbPort;
164
165 Assert(cbRest || pszRaw[idxRaw - 1] == PF_FIELD_SEPARATOR); /* we are 1 char ahead */
166
167 char szPort[10];
168 RT_ZERO(szPort);
169
170 Assert(idxRaw > 0);
171 RTStrCopy(szPort, RT_MIN(sizeof(szPort), (size_t)(cbPort) + 1), pszRaw);
172
173 if (!(u16Port = RTStrToUInt16(szPort)))
174 return -1;
175
176 *pu16Port = u16Port;
177
178 return idxRaw;
179#endif
180}
181
182
183static int netPfStrAddressPortPairParse(char *pszRaw, size_t cchRaw,
184 char *pszAddress, int cbAddress,
185 bool fEmptyAddressAcceptable,
186 uint16_t *pu16Port)
187{
188 int idxRaw = 0;
189 int idxRawTotal = 0;
190
191 AssertPtrReturn(pszRaw, -1);
192 AssertPtrReturn(pszAddress, -1);
193 AssertPtrReturn(pu16Port, -2);
194
195 /* XXX: Here we should check 0 - ':' and 1 - '[' */
196 Assert( pszRaw[0] == PF_FIELD_SEPARATOR
197 && pszRaw[1] == PF_ADDRESS_FIELD_STARTS);
198
199 pszRaw++; /* field separator skip */
200 cchRaw--;
201 AssertReturn(cchRaw > 0, VERR_INVALID_PARAMETER);
202
203 idxRaw = 0;
204
205 if (pszRaw[0] == PF_ADDRESS_FIELD_STARTS)
206 {
207 idxRaw += netPfStrAddressParse(pszRaw,
208 cchRaw - idxRaw,
209 pszAddress,
210 cbAddress,
211 fEmptyAddressAcceptable);
212 if (idxRaw == -1)
213 return -1;
214
215 Assert(pszRaw[idxRaw] == PF_FIELD_SEPARATOR);
216 }
217 else return -1;
218
219 pszRaw += idxRaw;
220 idxRawTotal += idxRaw;
221 cchRaw -= idxRaw;
222
223 AssertReturn(cchRaw > 0, VERR_INVALID_PARAMETER);
224
225 idxRaw = 0;
226
227 Assert(pszRaw[0] == PF_FIELD_SEPARATOR);
228
229 if (pszRaw[0] == PF_FIELD_SEPARATOR)
230 {
231 idxRaw = netPfStrPortParse(pszRaw, pu16Port);
232
233 Assert(strlen(&pszRaw[idxRaw]) == 0 || pszRaw[idxRaw] == PF_FIELD_SEPARATOR);
234
235 if (idxRaw == -1)
236 return -2;
237
238 idxRawTotal += idxRaw;
239
240 return idxRawTotal + 1;
241 }
242 else return -1; /* trailing garbage in the address */
243}
244
245/* XXX: Having fIPv6 we might emprove adress verification comparing address length
246 * with INET[6]_ADDRLEN
247 *
248 */
249int netPfStrToPf(const char *pcszStrPortForward, bool fIPv6, PPORTFORWARDRULE pPfr)
250{
251/** r=bird: Redo from scratch? This is very hard to read. And it's going about
252 * things in a very complicated, potentially leaky (pszRaw) fashion. */
253
254 int proto;
255 uint16_t u16HostPort;
256 uint16_t u16GuestPort;
257 bool fTcpProto = false;
258
259 int idxRaw = 0;
260 int cbToken = 0;
261
262 AssertPtrReturn(pcszStrPortForward, VERR_INVALID_PARAMETER);
263 AssertPtrReturn(pPfr, VERR_INVALID_PARAMETER);
264
265 RT_ZERO(*pPfr);
266
267 char *pszHostAddr = &pPfr->szPfrHostAddr[0];
268 char *pszGuestAddr = &pPfr->szPfrGuestAddr[0];
269 char *pszName = &pPfr->szPfrName[0];
270
271 size_t cchRaw = strlen(pcszStrPortForward);
272
273 /* Minimal rule ":tcp:[]:0:[]:0" has got lenght 14 */
274 AssertReturn(cchRaw > 14, VERR_INVALID_PARAMETER);
275
276 char *pszRaw = RTStrDup(pcszStrPortForward);
277 AssertReturn(pszRaw, VERR_NO_MEMORY);
278
279 char *pszRawBegin = pszRaw;
280
281 /* name */
282 if (pszRaw[idxRaw] == PF_FIELD_SEPARATOR)
283 idxRaw = 1; /* begin of the next segment */
284 else
285 {
286 char *pszEndOfName = RTStrStr(pszRaw + 1, PF_STR_FIELD_SEPARATOR);
287 if (!pszEndOfName)
288 goto invalid_parameter;
289
290 cbToken = pszEndOfName - pszRaw; /* don't take : into account */
291 /* XXX it's unacceptable to have only name entry in PF */
292 AssertReturn(cbToken < (ssize_t)cchRaw, VERR_INVALID_PARAMETER);
293
294 if ( cbToken < 0
295 || (size_t)cbToken >= PF_NAMELEN)
296 goto invalid_parameter;
297
298 RTStrCopy(pszName,
299 RT_MIN((size_t)cbToken + 1, PF_NAMELEN),
300 pszRaw);
301 pszRaw += cbToken; /* move to separator */
302 cchRaw -= cbToken;
303 }
304
305 AssertReturn(pszRaw[0] == PF_FIELD_SEPARATOR, VERR_INVALID_PARAMETER);
306 /* protocol */
307
308 pszRaw++; /* skip separator */
309 cchRaw--;
310 idxRaw = 0;
311
312 if ( ( (fTcpProto = (RTStrNICmp(pszRaw, "tcp", 3) == 0))
313 || RTStrNICmp(pszRaw, "udp", 3) == 0)
314 && pszRaw[3] == PF_FIELD_SEPARATOR)
315 {
316 proto = (fTcpProto ? IPPROTO_TCP : IPPROTO_UDP);
317 idxRaw = 3;
318 }
319 else
320 goto invalid_parameter;
321
322 pszRaw += idxRaw;
323 cchRaw -= idxRaw;
324
325 idxRaw = netPfStrAddressPortPairParse(pszRaw, cchRaw,
326 pszHostAddr, INET6_ADDRSTRLEN,
327 true, &u16HostPort);
328 if (idxRaw < 0)
329 return VERR_INVALID_PARAMETER;
330
331 pszRaw += idxRaw;
332 cchRaw -= idxRaw;
333
334 Assert(pszRaw[0] == PF_FIELD_SEPARATOR);
335
336 idxRaw = netPfStrAddressPortPairParse(pszRaw, cchRaw,
337 pszGuestAddr, INET6_ADDRSTRLEN,
338 false, &u16GuestPort);
339
340 if (idxRaw < 0)
341 goto invalid_parameter;
342
343 /* XXX: fill the rule */
344 pPfr->fPfrIPv6 = fIPv6;
345 pPfr->iPfrProto = proto;
346
347 pPfr->u16PfrHostPort = u16HostPort;
348
349 if (*pszGuestAddr == '\0')
350 goto invalid_parameter; /* guest address should be defined */
351
352 pPfr->u16PfrGuestPort = u16GuestPort;
353
354 Log(("name: %s\n"
355 "proto: %d\n"
356 "host address: %s\n"
357 "host port: %d\n"
358 "guest address: %s\n"
359 "guest port:%d\n",
360 pszName, proto,
361 pszHostAddr, u16HostPort,
362 pszGuestAddr, u16GuestPort));
363
364 RTStrFree(pszRawBegin);
365 return VINF_SUCCESS;
366
367invalid_parameter:
368 RTStrFree(pszRawBegin);
369 if (pPfr)
370 RT_ZERO(*pPfr);
371 return VERR_INVALID_PARAMETER;
372}
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