VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/net/netaddrstr2.cpp@ 60963

Last change on this file since 60963 was 58438, checked in by vboxsync, 9 years ago

IPRT/net: add RTNetStrIsIPv4AddrAny, RTNetStrIsIPv6AddrAny.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1/* $Id: netaddrstr2.cpp 58438 2015-10-27 16:30:34Z vboxsync $ */
2/** @file
3 * IPRT - Network Address String Handling.
4 */
5
6/*
7 * Copyright (C) 2013-2015 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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/net.h>
33
34#include <iprt/asm.h>
35#include <iprt/mem.h>
36#include <iprt/string.h>
37#include <iprt/stream.h>
38#include "internal/string.h"
39
40
41DECLHIDDEN(int) rtNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr,
42 char **ppszNext)
43{
44 char *pszNext;
45 int rc;
46
47 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
48 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
49
50 rc = RTStrToUInt8Ex(pcszAddr, &pszNext, 10, &pAddr->au8[0]);
51 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
52 return VERR_INVALID_PARAMETER;
53 if (*pszNext++ != '.')
54 return VERR_INVALID_PARAMETER;
55
56 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[1]);
57 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
58 return VERR_INVALID_PARAMETER;
59 if (*pszNext++ != '.')
60 return VERR_INVALID_PARAMETER;
61
62 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[2]);
63 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
64 return VERR_INVALID_PARAMETER;
65 if (*pszNext++ != '.')
66 return VERR_INVALID_PARAMETER;
67
68 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[3]);
69 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES && rc != VWRN_TRAILING_CHARS)
70 return VERR_INVALID_PARAMETER;
71
72 if (ppszNext != NULL)
73 *ppszNext = pszNext;
74 return VINF_SUCCESS;
75}
76
77
78RTDECL(int) RTNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr,
79 char **ppszNext)
80{
81 return rtNetStrToIPv4AddrEx(pcszAddr, pAddr, ppszNext);
82}
83RT_EXPORT_SYMBOL(RTNetStrToIPv4AddrEx);
84
85
86RTDECL(int) RTNetStrToIPv4Addr(const char *pcszAddr, PRTNETADDRIPV4 pAddr)
87{
88 char *pszNext;
89 int rc;
90
91 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
92 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
93
94 pcszAddr = RTStrStripL(pcszAddr);
95 rc = rtNetStrToIPv4AddrEx(pcszAddr, pAddr, &pszNext);
96 if (rc != VINF_SUCCESS)
97 return VERR_INVALID_PARAMETER;
98
99 pszNext = RTStrStripL(pszNext);
100 if (*pszNext != '\0')
101 return VERR_INVALID_PARAMETER;
102
103 return VINF_SUCCESS;
104}
105RT_EXPORT_SYMBOL(RTNetStrToIPv4Addr);
106
107
108RTDECL(bool) RTNetIsIPv4AddrStr(const char *pcszAddr)
109{
110 RTNETADDRIPV4 addrIPv4;
111 char *pszNext;
112 int rc;
113
114 if (pcszAddr == NULL)
115 return false;
116
117 rc = rtNetStrToIPv4AddrEx(pcszAddr, &addrIPv4, &pszNext);
118 if (rc != VINF_SUCCESS)
119 return false;
120
121 if (*pszNext != '\0')
122 return false;
123
124 return true;
125}
126RT_EXPORT_SYMBOL(RTNetIsIPv4AddrStr);
127
128
129RTDECL(bool) RTNetStrIsIPv4AddrAny(const char *pcszAddr)
130{
131 RTNETADDRIPV4 addrIPv4;
132 char *pszNext;
133 int rc;
134
135 if (pcszAddr == NULL)
136 return false;
137
138 pcszAddr = RTStrStripL(pcszAddr);
139 rc = rtNetStrToIPv4AddrEx(pcszAddr, &addrIPv4, &pszNext);
140 if (rc != VINF_SUCCESS)
141 return false;
142
143 pszNext = RTStrStripL(pszNext);
144 if (*pszNext != '\0')
145 return false;
146
147 if (addrIPv4.u != 0u) /* INADDR_ANY? */
148 return false;
149
150 return true;
151}
152RT_EXPORT_SYMBOL(RTNetStrIsIPv4AddrAny);
153
154
155static int rtNetStrToHexGroup(const char *pcszValue, char **ppszNext,
156 uint16_t *pu16)
157{
158 char *pszNext;
159 int rc;
160
161 rc = RTStrToUInt16Ex(pcszValue, &pszNext, 16, pu16);
162 if (RT_FAILURE(rc))
163 return rc;
164
165 if ( rc != VINF_SUCCESS
166 && rc != VWRN_TRAILING_CHARS
167 && rc != VWRN_TRAILING_SPACES)
168 {
169 return -rc; /* convert warning to error */
170 }
171
172 /* parser always accepts 0x prefix */
173 if (pcszValue[0] == '0' && (pcszValue[1] == 'x' || pcszValue[1] == 'X'))
174 {
175 if (pu16)
176 *pu16 = 0;
177 if (ppszNext)
178 *ppszNext = (/* UNCONST */ char *)pcszValue + 1; /* to 'x' */
179 return VWRN_TRAILING_CHARS;
180 }
181
182 /* parser accepts leading zeroes "000000f" */
183 if (pszNext - pcszValue > 4)
184 return VERR_PARSE_ERROR;
185
186 if (ppszNext)
187 *ppszNext = pszNext;
188 return rc;
189}
190
191
192/*
193 * This function deals only with the hex-group IPv6 address syntax
194 * proper (with possible embedded IPv4).
195 */
196DECLHIDDEN(int) rtNetStrToIPv6AddrBase(const char *pcszAddr, PRTNETADDRIPV6 pAddrResult,
197 char **ppszNext)
198{
199 RTNETADDRIPV6 ipv6;
200 RTNETADDRIPV4 ipv4;
201 const char *pcszPos;
202 char *pszNext;
203 int iGroup;
204 uint16_t u16;
205 int rc;
206
207 memset(&ipv6, 0, sizeof(ipv6));
208
209 pcszPos = pcszAddr;
210
211 if (pcszPos[0] == ':') /* compressed zero run at the beginning? */
212 {
213 if (pcszPos[1] != ':')
214 return VERR_PARSE_ERROR;
215
216 pcszPos += 2; /* skip over "::" */
217 pszNext = (/* UNCONST */ char *)pcszPos;
218 iGroup = 1;
219 }
220 else
221 {
222 /*
223 * Scan forward until we either get complete address or find
224 * "::" compressed zero run.
225 */
226 for (iGroup = 0; iGroup < 8; ++iGroup)
227 {
228 /* check for embedded IPv4 at the end */
229 if (iGroup == 6)
230 {
231 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
232 if (rc == VINF_SUCCESS)
233 {
234 ipv6.au32[3] = ipv4.au32[0];
235 iGroup = 8; /* filled 6 and 7 */
236 break; /* we are done */
237 }
238 }
239
240 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
241 if (RT_FAILURE(rc))
242 return VERR_PARSE_ERROR;
243
244 ipv6.au16[iGroup] = RT_H2N_U16(u16);
245
246 if (iGroup == 7)
247 pcszPos = pszNext;
248 else
249 {
250 /* skip the colon that delimits this group */
251 if (*pszNext != ':')
252 return VERR_PARSE_ERROR;
253 pcszPos = pszNext + 1;
254
255 /* compressed zero run? */
256 if (*pcszPos == ':')
257 {
258 ++pcszPos; /* skip over :: */
259 pszNext += 2; /* skip over :: (in case we are done) */
260 iGroup += 2; /* current field and the zero in the next */
261 break;
262 }
263 }
264 }
265 }
266
267 if (iGroup != 8)
268 {
269 /*
270 * iGroup is the first group that can be filled by the part of
271 * the address after "::".
272 */
273 RTNETADDRIPV6 ipv6Tail;
274 const int iMaybeStart = iGroup;
275 int j;
276
277 memset(&ipv6Tail, 0, sizeof(ipv6Tail));
278
279 /*
280 * We try to accept longest match; we'll shift if necessary.
281 * Unlike the first loop, a failure to parse a group doesn't
282 * mean invalid address.
283 */
284 for (; iGroup < 8; ++iGroup)
285 {
286 /* check for embedded IPv4 at the end */
287 if (iGroup <= 6)
288 {
289 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
290 if (rc == VINF_SUCCESS)
291 {
292 ipv6Tail.au16[iGroup] = ipv4.au16[0];
293 ipv6Tail.au16[iGroup + 1] = ipv4.au16[1];
294 iGroup = iGroup + 2; /* these two are done */
295 break; /* the rest is trailer */
296 }
297 }
298
299 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
300 if (RT_FAILURE(rc))
301 break;
302
303 ipv6Tail.au16[iGroup] = RT_H2N_U16(u16);
304
305 if (iGroup == 7)
306 pcszPos = pszNext;
307 else
308 {
309 if (*pszNext != ':')
310 {
311 ++iGroup; /* this one is done */
312 break; /* the rest is trailer */
313 }
314
315 pcszPos = pszNext + 1;
316 }
317 }
318
319 for (j = 7, --iGroup; iGroup >= iMaybeStart; --j, --iGroup)
320 ipv6.au16[j] = ipv6Tail.au16[iGroup];
321 }
322
323 if (pAddrResult != NULL)
324 memcpy(pAddrResult, &ipv6, sizeof(ipv6));
325 if (ppszNext != NULL)
326 *ppszNext = pszNext;
327 return VINF_SUCCESS;
328}
329
330
331DECLHIDDEN(int) rtNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
332 char **ppszZone, char **ppszNext)
333{
334 char *pszNext, *pszZone;
335 int rc;
336
337 rc = rtNetStrToIPv6AddrBase(pcszAddr, pAddr, &pszNext);
338 if (RT_FAILURE(rc))
339 return rc;
340
341 if (*pszNext != '%') /* is there a zone id? */
342 {
343 pszZone = NULL;
344 }
345 else
346 {
347 pszZone = pszNext + 1; /* skip '%' zone id delimiter */
348 if (*pszZone == '\0')
349 return VERR_PARSE_ERROR; /* empty zone id */
350
351 /*
352 * XXX: this is speculative as zone id syntax is
353 * implementation dependent, so we kinda guess here (accepting
354 * unreserved characters from URI syntax).
355 */
356 for (pszNext = pszZone; *pszNext != '\0'; ++pszNext)
357 {
358 const char c = *pszNext;
359 if ( !('0' <= c && c <= '9')
360 && !('a' <= c && c <= 'z')
361 && !('A' <= c && c <= 'Z')
362 && c != '_'
363 && c != '.'
364 && c != '-'
365 && c != '~')
366 {
367 break;
368 }
369 }
370 }
371
372 if (ppszZone != NULL)
373 *ppszZone = pszZone;
374 if (ppszNext != NULL)
375 *ppszNext = pszNext;
376
377 if (*pszNext == '\0') /* all input string consumed */
378 return VINF_SUCCESS;
379 else
380 {
381 while (*pszNext == ' ' || *pszNext == '\t')
382 ++pszNext;
383 if (*pszNext == '\0')
384 return VWRN_TRAILING_SPACES;
385 else
386 return VWRN_TRAILING_CHARS;
387 }
388}
389
390
391RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
392 char **ppszNext)
393{
394 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
395 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
396
397 return rtNetStrToIPv6AddrBase(pcszAddr, pAddr, ppszNext);
398}
399RT_EXPORT_SYMBOL(RTNetStrToIPv6AddrEx);
400
401
402RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
403 char **ppszZone)
404{
405 int rc;
406
407 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
408 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
409 AssertPtrReturn(ppszZone, VERR_INVALID_PARAMETER);
410
411 pcszAddr = RTStrStripL(pcszAddr);
412 rc = rtNetStrToIPv6AddrEx(pcszAddr, pAddr, ppszZone, NULL);
413 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
414 return VERR_INVALID_PARAMETER;
415
416 return VINF_SUCCESS;
417}
418RT_EXPORT_SYMBOL(RTNetStrToIPv6Addr);
419
420
421RTDECL(bool) RTNetIsIPv6AddrStr(const char *pcszAddr)
422{
423 RTNETADDRIPV6 addrIPv6;
424 int rc;
425
426 if (pcszAddr == NULL)
427 return false;
428
429 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, NULL, NULL);
430 if (rc != VINF_SUCCESS)
431 return false;
432
433 return true;
434}
435RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr);
436
437
438RTDECL(bool) RTNetStrIsIPv6AddrAny(const char *pcszAddr)
439{
440 RTNETADDRIPV6 addrIPv6;
441 char *pszZone, *pszNext;
442 int rc;
443
444 if (pcszAddr == NULL)
445 return false;
446
447 pcszAddr = RTStrStripL(pcszAddr);
448 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, &pszZone, &pszNext);
449 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
450 return false;
451
452 if (pszZone != NULL)
453 return false;
454
455 if (addrIPv6.s.Lo != 0 || addrIPv6.s.Hi != 0) /* in6addr_any? */
456 return false;
457
458 return true;
459}
460RT_EXPORT_SYMBOL(RTNetStrIsIPv6AddrAny);
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