VirtualBox

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

Last change on this file since 69111 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 KB
Line 
1/* $Id: netaddrstr2.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * IPRT - Network Address String Handling.
4 */
5
6/*
7 * Copyright (C) 2013-2017 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
155RTDECL(int) RTNetMaskToPrefixIPv4(PCRTNETADDRIPV4 pMask, int *piPrefix)
156{
157 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
158
159 if (pMask->u == 0)
160 {
161 if (piPrefix != NULL)
162 *piPrefix = 0;
163 return VINF_SUCCESS;
164 }
165
166 const uint32_t uMask = RT_N2H_U32(pMask->u);
167
168 uint32_t uPrefixMask = UINT32_C(0xffffffff);
169 int iPrefixLen = 32;
170
171 while (iPrefixLen > 0)
172 {
173 if (uMask == uPrefixMask)
174 {
175 if (piPrefix != NULL)
176 *piPrefix = iPrefixLen;
177 return VINF_SUCCESS;
178 }
179
180 --iPrefixLen;
181 uPrefixMask <<= 1;
182 }
183
184 return VERR_INVALID_PARAMETER;
185}
186RT_EXPORT_SYMBOL(RTNetMaskToPrefixIPv4);
187
188
189RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask)
190{
191 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
192
193 if (RT_UNLIKELY(iPrefix < 0 || 32 < iPrefix))
194 return VERR_INVALID_PARAMETER;
195
196 if (RT_LIKELY(iPrefix != 0))
197 pMask->u = RT_H2N_U32(UINT32_C(0xffffffff) << (32 - iPrefix));
198 else /* avoid UB in the shift */
199 pMask->u = 0;
200
201 return VINF_SUCCESS;
202}
203RT_EXPORT_SYMBOL(RTNetPrefixToMaskIPv4);
204
205
206static int rtNetStrToHexGroup(const char *pcszValue, char **ppszNext,
207 uint16_t *pu16)
208{
209 char *pszNext;
210 int rc;
211
212 rc = RTStrToUInt16Ex(pcszValue, &pszNext, 16, pu16);
213 if (RT_FAILURE(rc))
214 return rc;
215
216 if ( rc != VINF_SUCCESS
217 && rc != VWRN_TRAILING_CHARS
218 && rc != VWRN_TRAILING_SPACES)
219 {
220 return -rc; /* convert warning to error */
221 }
222
223 /* parser always accepts 0x prefix */
224 if (pcszValue[0] == '0' && (pcszValue[1] == 'x' || pcszValue[1] == 'X'))
225 {
226 if (pu16)
227 *pu16 = 0;
228 if (ppszNext)
229 *ppszNext = (/* UNCONST */ char *)pcszValue + 1; /* to 'x' */
230 return VWRN_TRAILING_CHARS;
231 }
232
233 /* parser accepts leading zeroes "000000f" */
234 if (pszNext - pcszValue > 4)
235 return VERR_PARSE_ERROR;
236
237 if (ppszNext)
238 *ppszNext = pszNext;
239 return rc;
240}
241
242
243/*
244 * This function deals only with the hex-group IPv6 address syntax
245 * proper (with possible embedded IPv4).
246 */
247DECLHIDDEN(int) rtNetStrToIPv6AddrBase(const char *pcszAddr, PRTNETADDRIPV6 pAddrResult,
248 char **ppszNext)
249{
250 RTNETADDRIPV6 ipv6;
251 RTNETADDRIPV4 ipv4;
252 const char *pcszPos;
253 char *pszNext;
254 int iGroup;
255 uint16_t u16;
256 int rc;
257
258 RT_ZERO(ipv6);
259
260 pcszPos = pcszAddr;
261
262 if (pcszPos[0] == ':') /* compressed zero run at the beginning? */
263 {
264 if (pcszPos[1] != ':')
265 return VERR_PARSE_ERROR;
266
267 pcszPos += 2; /* skip over "::" */
268 pszNext = (/* UNCONST */ char *)pcszPos;
269 iGroup = 1;
270 }
271 else
272 {
273 /*
274 * Scan forward until we either get complete address or find
275 * "::" compressed zero run.
276 */
277 pszNext = NULL; /* (MSC incorrectly thinks it may be used unitialized) */
278 for (iGroup = 0; iGroup < 8; ++iGroup)
279 {
280 /* check for embedded IPv4 at the end */
281 if (iGroup == 6)
282 {
283 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
284 if (rc == VINF_SUCCESS)
285 {
286 ipv6.au32[3] = ipv4.au32[0];
287 iGroup = 8; /* filled 6 and 7 */
288 break; /* we are done */
289 }
290 }
291
292 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
293 if (RT_FAILURE(rc))
294 return VERR_PARSE_ERROR;
295
296 ipv6.au16[iGroup] = RT_H2N_U16(u16);
297
298 if (iGroup == 7)
299 pcszPos = pszNext;
300 else
301 {
302 /* skip the colon that delimits this group */
303 if (*pszNext != ':')
304 return VERR_PARSE_ERROR;
305 pcszPos = pszNext + 1;
306
307 /* compressed zero run? */
308 if (*pcszPos == ':')
309 {
310 ++pcszPos; /* skip over :: */
311 pszNext += 2; /* skip over :: (in case we are done) */
312 iGroup += 2; /* current field and the zero in the next */
313 break;
314 }
315 }
316 }
317 }
318
319 if (iGroup != 8)
320 {
321 /*
322 * iGroup is the first group that can be filled by the part of
323 * the address after "::".
324 */
325 RTNETADDRIPV6 ipv6Tail;
326 const int iMaybeStart = iGroup;
327 int j;
328
329 RT_ZERO(ipv6Tail);
330
331 /*
332 * We try to accept longest match; we'll shift if necessary.
333 * Unlike the first loop, a failure to parse a group doesn't
334 * mean invalid address.
335 */
336 for (; iGroup < 8; ++iGroup)
337 {
338 /* check for embedded IPv4 at the end */
339 if (iGroup <= 6)
340 {
341 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
342 if (rc == VINF_SUCCESS)
343 {
344 ipv6Tail.au16[iGroup] = ipv4.au16[0];
345 ipv6Tail.au16[iGroup + 1] = ipv4.au16[1];
346 iGroup = iGroup + 2; /* these two are done */
347 break; /* the rest is trailer */
348 }
349 }
350
351 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
352 if (RT_FAILURE(rc))
353 break;
354
355 ipv6Tail.au16[iGroup] = RT_H2N_U16(u16);
356
357 if (iGroup == 7)
358 pcszPos = pszNext;
359 else
360 {
361 if (*pszNext != ':')
362 {
363 ++iGroup; /* this one is done */
364 break; /* the rest is trailer */
365 }
366
367 pcszPos = pszNext + 1;
368 }
369 }
370
371 for (j = 7, --iGroup; iGroup >= iMaybeStart; --j, --iGroup)
372 ipv6.au16[j] = ipv6Tail.au16[iGroup];
373 }
374
375 if (pAddrResult != NULL)
376 memcpy(pAddrResult, &ipv6, sizeof(ipv6));
377 if (ppszNext != NULL)
378 *ppszNext = pszNext;
379 return VINF_SUCCESS;
380}
381
382
383DECLHIDDEN(int) rtNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
384 char **ppszZone, char **ppszNext)
385{
386 char *pszNext, *pszZone;
387 int rc;
388
389 rc = rtNetStrToIPv6AddrBase(pcszAddr, pAddr, &pszNext);
390 if (RT_FAILURE(rc))
391 return rc;
392
393 if (*pszNext != '%') /* is there a zone id? */
394 {
395 pszZone = NULL;
396 }
397 else
398 {
399 pszZone = pszNext + 1; /* skip '%' zone id delimiter */
400 if (*pszZone == '\0')
401 return VERR_PARSE_ERROR; /* empty zone id */
402
403 /*
404 * XXX: this is speculative as zone id syntax is
405 * implementation dependent, so we kinda guess here (accepting
406 * unreserved characters from URI syntax).
407 */
408 for (pszNext = pszZone; *pszNext != '\0'; ++pszNext)
409 {
410 const char c = *pszNext;
411 if ( !('0' <= c && c <= '9')
412 && !('a' <= c && c <= 'z')
413 && !('A' <= c && c <= 'Z')
414 && c != '_'
415 && c != '.'
416 && c != '-'
417 && c != '~')
418 {
419 break;
420 }
421 }
422 }
423
424 if (ppszZone != NULL)
425 *ppszZone = pszZone;
426 if (ppszNext != NULL)
427 *ppszNext = pszNext;
428
429 if (*pszNext == '\0') /* all input string consumed */
430 return VINF_SUCCESS;
431 else
432 {
433 while (*pszNext == ' ' || *pszNext == '\t')
434 ++pszNext;
435 if (*pszNext == '\0')
436 return VWRN_TRAILING_SPACES;
437 else
438 return VWRN_TRAILING_CHARS;
439 }
440}
441
442
443RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
444 char **ppszNext)
445{
446 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
447 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
448
449 return rtNetStrToIPv6AddrBase(pcszAddr, pAddr, ppszNext);
450}
451RT_EXPORT_SYMBOL(RTNetStrToIPv6AddrEx);
452
453
454RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
455 char **ppszZone)
456{
457 int rc;
458
459 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
460 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
461 AssertPtrReturn(ppszZone, VERR_INVALID_PARAMETER);
462
463 pcszAddr = RTStrStripL(pcszAddr);
464 rc = rtNetStrToIPv6AddrEx(pcszAddr, pAddr, ppszZone, NULL);
465 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
466 return VERR_INVALID_PARAMETER;
467
468 return VINF_SUCCESS;
469}
470RT_EXPORT_SYMBOL(RTNetStrToIPv6Addr);
471
472
473RTDECL(bool) RTNetIsIPv6AddrStr(const char *pcszAddr)
474{
475 RTNETADDRIPV6 addrIPv6;
476 int rc;
477
478 if (pcszAddr == NULL)
479 return false;
480
481 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, NULL, NULL);
482 if (rc != VINF_SUCCESS)
483 return false;
484
485 return true;
486}
487RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr);
488
489
490RTDECL(bool) RTNetStrIsIPv6AddrAny(const char *pcszAddr)
491{
492 RTNETADDRIPV6 addrIPv6;
493 char *pszZone, *pszNext;
494 int rc;
495
496 if (pcszAddr == NULL)
497 return false;
498
499 pcszAddr = RTStrStripL(pcszAddr);
500 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, &pszZone, &pszNext);
501 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
502 return false;
503
504 if (pszZone != NULL)
505 return false;
506
507 if (addrIPv6.s.Lo != 0 || addrIPv6.s.Hi != 0) /* in6addr_any? */
508 return false;
509
510 return true;
511}
512RT_EXPORT_SYMBOL(RTNetStrIsIPv6AddrAny);
513
514
515RTDECL(int) RTNetMaskToPrefixIPv6(PCRTNETADDRIPV6 pMask, int *piPrefix)
516{
517 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
518
519 int iPrefix = 0;
520 unsigned int i;
521
522 for (i = 0; i < RT_ELEMENTS(pMask->au8); ++i)
523 {
524 int iBits;
525 switch (pMask->au8[i])
526 {
527 case 0x00: iBits = 0; break;
528 case 0x80: iBits = 1; break;
529 case 0xc0: iBits = 2; break;
530 case 0xe0: iBits = 3; break;
531 case 0xf0: iBits = 4; break;
532 case 0xf8: iBits = 5; break;
533 case 0xfc: iBits = 6; break;
534 case 0xfe: iBits = 7; break;
535 case 0xff: iBits = 8; break;
536 default: /* non-contiguous mask */
537 return VERR_INVALID_PARAMETER;
538 }
539
540 iPrefix += iBits;
541 if (iBits != 8)
542 break;
543 }
544
545 for (++i; i < RT_ELEMENTS(pMask->au8); ++i)
546 if (pMask->au8[i] != 0)
547 return VERR_INVALID_PARAMETER;
548
549 if (piPrefix != NULL)
550 *piPrefix = iPrefix;
551 return VINF_SUCCESS;
552}
553RT_EXPORT_SYMBOL(RTNetMaskToPrefixIPv6);
554
555
556RTDECL(int) RTNetPrefixToMaskIPv6(int iPrefix, PRTNETADDRIPV6 pMask)
557{
558 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
559
560 if (RT_UNLIKELY(iPrefix < 0 || 128 < iPrefix))
561 return VERR_INVALID_PARAMETER;
562
563 for (unsigned int i = 0; i < RT_ELEMENTS(pMask->au32); ++i)
564 {
565 if (iPrefix == 0)
566 {
567 pMask->au32[i] = 0;
568 }
569 else if (iPrefix >= 32)
570 {
571 pMask->au32[i] = UINT32_C(0xffffffff);
572 iPrefix -= 32;
573 }
574 else
575 {
576 pMask->au32[i] = RT_H2N_U32(UINT32_C(0xffffffff) << (32 - iPrefix));
577 iPrefix = 0;
578 }
579 }
580
581 return VINF_SUCCESS;
582}
583RT_EXPORT_SYMBOL(RTNetPrefixToMaskIPv6);
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