VirtualBox

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

Last change on this file was 99775, checked in by vboxsync, 12 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.0 KB
Line 
1/* $Id: netaddrstr2.cpp 99775 2023-05-12 12:21:58Z vboxsync $ */
2/** @file
3 * IPRT - Network Address String Handling.
4 */
5
6/*
7 * Copyright (C) 2013-2023 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 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "internal/iprt.h"
42#include <iprt/net.h>
43
44#include <iprt/asm.h>
45#include <iprt/errcore.h>
46#include <iprt/mem.h>
47#include <iprt/string.h>
48#include <iprt/stream.h>
49#include "internal/string.h"
50
51
52static int rtNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr,
53 char **ppszNext)
54{
55 char *pszNext;
56 int rc;
57
58 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
59 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
60
61 rc = RTStrToUInt8Ex(pcszAddr, &pszNext, 10, &pAddr->au8[0]);
62 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
63 return VERR_INVALID_PARAMETER;
64 if (*pszNext++ != '.')
65 return VERR_INVALID_PARAMETER;
66
67 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[1]);
68 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
69 return VERR_INVALID_PARAMETER;
70 if (*pszNext++ != '.')
71 return VERR_INVALID_PARAMETER;
72
73 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[2]);
74 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
75 return VERR_INVALID_PARAMETER;
76 if (*pszNext++ != '.')
77 return VERR_INVALID_PARAMETER;
78
79 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[3]);
80 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES && rc != VWRN_TRAILING_CHARS)
81 return VERR_INVALID_PARAMETER;
82
83 if (ppszNext != NULL)
84 *ppszNext = pszNext;
85 return rc;
86}
87
88
89RTDECL(int) RTNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr,
90 char **ppszNext)
91{
92 return rtNetStrToIPv4AddrEx(pcszAddr, pAddr, ppszNext);
93}
94RT_EXPORT_SYMBOL(RTNetStrToIPv4AddrEx);
95
96
97RTDECL(int) RTNetStrToIPv4Addr(const char *pcszAddr, PRTNETADDRIPV4 pAddr)
98{
99 char *pszNext;
100 int rc;
101
102 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
103 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
104
105 pcszAddr = RTStrStripL(pcszAddr);
106 rc = rtNetStrToIPv4AddrEx(pcszAddr, pAddr, &pszNext);
107 if (RT_FAILURE(rc) || rc == VWRN_TRAILING_CHARS)
108 return VERR_INVALID_PARAMETER;
109
110 return VINF_SUCCESS;
111}
112RT_EXPORT_SYMBOL(RTNetStrToIPv4Addr);
113
114
115RTDECL(bool) RTNetIsIPv4AddrStr(const char *pcszAddr)
116{
117 RTNETADDRIPV4 addrIPv4;
118 char *pszNext;
119 int rc;
120
121 if (pcszAddr == NULL)
122 return false;
123
124 rc = rtNetStrToIPv4AddrEx(pcszAddr, &addrIPv4, &pszNext);
125 if (rc != VINF_SUCCESS)
126 return false;
127
128 if (*pszNext != '\0')
129 return false;
130
131 return true;
132}
133RT_EXPORT_SYMBOL(RTNetIsIPv4AddrStr);
134
135
136RTDECL(bool) RTNetStrIsIPv4AddrAny(const char *pcszAddr)
137{
138 RTNETADDRIPV4 addrIPv4;
139 char *pszNext;
140 int rc;
141
142 if (pcszAddr == NULL)
143 return false;
144
145 pcszAddr = RTStrStripL(pcszAddr);
146 rc = rtNetStrToIPv4AddrEx(pcszAddr, &addrIPv4, &pszNext);
147 if (RT_FAILURE(rc) || rc == VWRN_TRAILING_CHARS)
148 return false;
149
150 if (addrIPv4.u != 0u) /* INADDR_ANY? */
151 return false;
152
153 return true;
154}
155RT_EXPORT_SYMBOL(RTNetStrIsIPv4AddrAny);
156
157
158RTDECL(int) RTNetMaskToPrefixIPv4(PCRTNETADDRIPV4 pMask, int *piPrefix)
159{
160 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
161
162 if (pMask->u == 0)
163 {
164 if (piPrefix != NULL)
165 *piPrefix = 0;
166 return VINF_SUCCESS;
167 }
168
169 const uint32_t uMask = RT_N2H_U32(pMask->u);
170
171 uint32_t uPrefixMask = UINT32_C(0xffffffff);
172 int iPrefixLen = 32;
173
174 while (iPrefixLen > 0)
175 {
176 if (uMask == uPrefixMask)
177 {
178 if (piPrefix != NULL)
179 *piPrefix = iPrefixLen;
180 return VINF_SUCCESS;
181 }
182
183 --iPrefixLen;
184 uPrefixMask <<= 1;
185 }
186
187 return VERR_INVALID_PARAMETER;
188}
189RT_EXPORT_SYMBOL(RTNetMaskToPrefixIPv4);
190
191
192RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask)
193{
194 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
195
196 if (RT_UNLIKELY(iPrefix < 0 || 32 < iPrefix))
197 return VERR_INVALID_PARAMETER;
198
199 if (RT_LIKELY(iPrefix != 0))
200 pMask->u = RT_H2N_U32(UINT32_C(0xffffffff) << (32 - iPrefix));
201 else /* avoid UB in the shift */
202 pMask->u = 0;
203
204 return VINF_SUCCESS;
205}
206RT_EXPORT_SYMBOL(RTNetPrefixToMaskIPv4);
207
208
209RTDECL(int) RTNetStrToIPv4Cidr(const char *pcszAddr, PRTNETADDRIPV4 pAddr, int *piPrefix)
210{
211 RTNETADDRIPV4 Addr, Mask;
212 uint8_t u8Prefix;
213 char *pszNext;
214 int rc;
215
216 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
217 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
218 AssertPtrReturn(piPrefix, VERR_INVALID_PARAMETER);
219
220 pcszAddr = RTStrStripL(pcszAddr);
221 rc = rtNetStrToIPv4AddrEx(pcszAddr, &Addr, &pszNext);
222 if (RT_FAILURE(rc))
223 return rc;
224
225 /*
226 * If the prefix is missing, treat is as exact (/32) address
227 * specification.
228 */
229 if (*pszNext == '\0' || rc == VWRN_TRAILING_SPACES)
230 {
231 *pAddr = Addr;
232 *piPrefix = 32;
233 return VINF_SUCCESS;
234 }
235
236 /*
237 * Be flexible about the way the prefix is specified after the
238 * slash: accept both the prefix length and the netmask, and for
239 * the latter accept both dotted-decimal and hex. The inputs we
240 * convert here are likely coming from a user and people have
241 * different preferences. Sometimes they just remember specific
242 * different networks in specific formats!
243 */
244 if (*pszNext == '/')
245 ++pszNext;
246 else
247 return VERR_INVALID_PARAMETER;
248
249 /* .../0x... is a hex mask */
250 if (pszNext[0] == '0' && (pszNext[1] == 'x' || pszNext[1] == 'X'))
251 {
252 rc = RTStrToUInt32Ex(pszNext, &pszNext, 16, &Mask.u);
253 if (rc == VINF_SUCCESS || rc == VWRN_TRAILING_SPACES)
254 Mask.u = RT_H2N_U32(Mask.u);
255 else
256 return VERR_INVALID_PARAMETER;
257
258 int iPrefix;
259 rc = RTNetMaskToPrefixIPv4(&Mask, &iPrefix);
260 if (RT_SUCCESS(rc))
261 u8Prefix = (uint8_t)iPrefix;
262 else
263 return VERR_INVALID_PARAMETER;
264 }
265 else
266 {
267 char *pszLookAhead;
268 uint32_t u32;
269 rc = RTStrToUInt32Ex(pszNext, &pszLookAhead, 10, &u32);
270
271 /* single number after the slash is prefix length */
272 if (rc == VINF_SUCCESS || rc == VWRN_TRAILING_SPACES)
273 {
274 if (u32 <= 32)
275 u8Prefix = (uint8_t)u32;
276 else
277 return VERR_INVALID_PARAMETER;
278 }
279 /* a number followed by more stuff, may be a dotted-decimal */
280 else if (rc == VWRN_TRAILING_CHARS)
281 {
282 if (*pszLookAhead != '.') /* don't even bother checking */
283 return VERR_INVALID_PARAMETER;
284
285 rc = rtNetStrToIPv4AddrEx(pszNext, &Mask, &pszNext);
286 if (rc == VINF_SUCCESS || rc == VWRN_TRAILING_SPACES)
287 {
288 int iPrefix;
289 rc = RTNetMaskToPrefixIPv4(&Mask, &iPrefix);
290 if (RT_SUCCESS(rc))
291 u8Prefix = (uint8_t)iPrefix;
292 else
293 return VERR_INVALID_PARAMETER;
294 }
295 else
296 return VERR_INVALID_PARAMETER;
297 }
298 /* failed to convert to number */
299 else
300 return VERR_INVALID_PARAMETER;
301 }
302
303 if (u8Prefix > 32)
304 return VERR_INVALID_PARAMETER;
305
306 *pAddr = Addr;
307 *piPrefix = u8Prefix;
308 return VINF_SUCCESS;
309}
310RT_EXPORT_SYMBOL(RTNetStrToIPv4Cidr);
311
312
313static int rtNetStrToHexGroup(const char *pcszValue, char **ppszNext,
314 uint16_t *pu16)
315{
316 char *pszNext;
317 int rc;
318
319 rc = RTStrToUInt16Ex(pcszValue, &pszNext, 16, pu16);
320 if (RT_FAILURE(rc))
321 return rc;
322
323 if ( rc != VINF_SUCCESS
324 && rc != VWRN_TRAILING_CHARS
325 && rc != VWRN_TRAILING_SPACES)
326 {
327 return -rc; /* convert warning to error */
328 }
329
330 /* parser always accepts 0x prefix */
331 if (pcszValue[0] == '0' && (pcszValue[1] == 'x' || pcszValue[1] == 'X'))
332 {
333 if (pu16)
334 *pu16 = 0;
335 if (ppszNext)
336 *ppszNext = (/* UNCONST */ char *)pcszValue + 1; /* to 'x' */
337 return VWRN_TRAILING_CHARS;
338 }
339
340 /* parser accepts leading zeroes "000000f" */
341 if (pszNext - pcszValue > 4)
342 return VERR_PARSE_ERROR;
343
344 if (ppszNext)
345 *ppszNext = pszNext;
346 return rc;
347}
348
349
350/*
351 * This function deals only with the hex-group IPv6 address syntax
352 * proper (with possible embedded IPv4).
353 */
354static int rtNetStrToIPv6AddrBase(const char *pcszAddr, PRTNETADDRIPV6 pAddrResult,
355 char **ppszNext)
356{
357 RTNETADDRIPV6 ipv6;
358 RTNETADDRIPV4 ipv4;
359 const char *pcszPos;
360 char *pszNext;
361 int iGroup;
362 uint16_t u16;
363 int rc;
364
365 RT_ZERO(ipv6);
366
367 pcszPos = pcszAddr;
368
369 if (pcszPos[0] == ':') /* compressed zero run at the beginning? */
370 {
371 if (pcszPos[1] != ':')
372 return VERR_PARSE_ERROR;
373
374 pcszPos += 2; /* skip over "::" */
375 pszNext = (/* UNCONST */ char *)pcszPos;
376 iGroup = 1;
377 }
378 else
379 {
380 /*
381 * Scan forward until we either get complete address or find
382 * "::" compressed zero run.
383 */
384 pszNext = NULL; /* (MSC incorrectly thinks it may be used unitialized) */
385 for (iGroup = 0; iGroup < 8; ++iGroup)
386 {
387 /* check for embedded IPv4 at the end */
388 if (iGroup == 6)
389 {
390 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
391 if (rc == VINF_SUCCESS)
392 {
393 ipv6.au32[3] = ipv4.au32[0];
394 iGroup = 8; /* filled 6 and 7 */
395 break; /* we are done */
396 }
397 }
398
399 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
400 if (RT_FAILURE(rc))
401 return VERR_PARSE_ERROR;
402
403 ipv6.au16[iGroup] = RT_H2N_U16(u16);
404
405 if (iGroup == 7)
406 pcszPos = pszNext;
407 else
408 {
409 /* skip the colon that delimits this group */
410 if (*pszNext != ':')
411 return VERR_PARSE_ERROR;
412 pcszPos = pszNext + 1;
413
414 /* compressed zero run? */
415 if (*pcszPos == ':')
416 {
417 ++pcszPos; /* skip over :: */
418 pszNext += 2; /* skip over :: (in case we are done) */
419 iGroup += 2; /* current field and the zero in the next */
420 break;
421 }
422 }
423 }
424 }
425
426 if (iGroup != 8)
427 {
428 /*
429 * iGroup is the first group that can be filled by the part of
430 * the address after "::".
431 */
432 RTNETADDRIPV6 ipv6Tail;
433 const int iMaybeStart = iGroup;
434 int j;
435
436 RT_ZERO(ipv6Tail);
437
438 /*
439 * We try to accept longest match; we'll shift if necessary.
440 * Unlike the first loop, a failure to parse a group doesn't
441 * mean invalid address.
442 */
443 for (; iGroup < 8; ++iGroup)
444 {
445 /* check for embedded IPv4 at the end */
446 if (iGroup <= 6)
447 {
448 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
449 if (rc == VINF_SUCCESS)
450 {
451 ipv6Tail.au16[iGroup] = ipv4.au16[0];
452 ipv6Tail.au16[iGroup + 1] = ipv4.au16[1];
453 iGroup = iGroup + 2; /* these two are done */
454 break; /* the rest is trailer */
455 }
456 }
457
458 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
459 if (RT_FAILURE(rc))
460 break;
461
462 ipv6Tail.au16[iGroup] = RT_H2N_U16(u16);
463
464 if (iGroup == 7)
465 pcszPos = pszNext;
466 else
467 {
468 if (*pszNext != ':')
469 {
470 ++iGroup; /* this one is done */
471 break; /* the rest is trailer */
472 }
473
474 pcszPos = pszNext + 1;
475 }
476 }
477
478 for (j = 7, --iGroup; iGroup >= iMaybeStart; --j, --iGroup)
479 ipv6.au16[j] = ipv6Tail.au16[iGroup];
480 }
481
482 if (pAddrResult != NULL)
483 memcpy(pAddrResult, &ipv6, sizeof(ipv6));
484 if (ppszNext != NULL)
485 *ppszNext = pszNext;
486 return VINF_SUCCESS;
487}
488
489
490static int rtNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
491 char **ppszZone, char **ppszNext)
492{
493 char *pszNext, *pszZone;
494 int rc;
495
496 rc = rtNetStrToIPv6AddrBase(pcszAddr, pAddr, &pszNext);
497 if (RT_FAILURE(rc))
498 return rc;
499
500 if (*pszNext != '%') /* is there a zone id? */
501 {
502 pszZone = NULL;
503 }
504 else
505 {
506 pszZone = pszNext + 1; /* skip '%' zone id delimiter */
507 if (*pszZone == '\0')
508 return VERR_PARSE_ERROR; /* empty zone id */
509
510 /*
511 * XXX: this is speculative as zone id syntax is
512 * implementation dependent, so we kinda guess here (accepting
513 * unreserved characters from URI syntax).
514 */
515 for (pszNext = pszZone; *pszNext != '\0'; ++pszNext)
516 {
517 const char c = *pszNext;
518 if ( !('0' <= c && c <= '9')
519 && !('a' <= c && c <= 'z')
520 && !('A' <= c && c <= 'Z')
521 && c != '_'
522 && c != '.'
523 && c != '-'
524 && c != '~')
525 {
526 break;
527 }
528 }
529 }
530
531 if (ppszZone != NULL)
532 *ppszZone = pszZone;
533 if (ppszNext != NULL)
534 *ppszNext = pszNext;
535
536 if (*pszNext == '\0') /* all input string consumed */
537 return VINF_SUCCESS;
538 else
539 {
540 while (*pszNext == ' ' || *pszNext == '\t')
541 ++pszNext;
542 if (*pszNext == '\0')
543 return VWRN_TRAILING_SPACES;
544 else
545 return VWRN_TRAILING_CHARS;
546 }
547}
548
549
550RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
551 char **ppszNext)
552{
553 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
554 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
555
556 return rtNetStrToIPv6AddrBase(pcszAddr, pAddr, ppszNext);
557}
558RT_EXPORT_SYMBOL(RTNetStrToIPv6AddrEx);
559
560
561RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
562 char **ppszZone)
563{
564 int rc;
565
566 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
567 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
568 AssertPtrReturn(ppszZone, VERR_INVALID_PARAMETER);
569
570 pcszAddr = RTStrStripL(pcszAddr);
571 rc = rtNetStrToIPv6AddrEx(pcszAddr, pAddr, ppszZone, NULL);
572 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
573 return VERR_INVALID_PARAMETER;
574
575 return VINF_SUCCESS;
576}
577RT_EXPORT_SYMBOL(RTNetStrToIPv6Addr);
578
579
580RTDECL(bool) RTNetIsIPv6AddrStr(const char *pcszAddr)
581{
582 RTNETADDRIPV6 addrIPv6;
583 int rc;
584
585 if (pcszAddr == NULL)
586 return false;
587
588 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, NULL, NULL);
589 if (rc != VINF_SUCCESS)
590 return false;
591
592 return true;
593}
594RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr);
595
596
597RTDECL(bool) RTNetStrIsIPv6AddrAny(const char *pcszAddr)
598{
599 RTNETADDRIPV6 addrIPv6;
600 char *pszZone, *pszNext;
601 int rc;
602
603 if (pcszAddr == NULL)
604 return false;
605
606 pcszAddr = RTStrStripL(pcszAddr);
607 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, &pszZone, &pszNext);
608 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
609 return false;
610
611 if (pszZone != NULL)
612 return false;
613
614 if (addrIPv6.s.Lo != 0 || addrIPv6.s.Hi != 0) /* in6addr_any? */
615 return false;
616
617 return true;
618}
619RT_EXPORT_SYMBOL(RTNetStrIsIPv6AddrAny);
620
621
622RTDECL(int) RTNetMaskToPrefixIPv6(PCRTNETADDRIPV6 pMask, int *piPrefix)
623{
624 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
625
626 int iPrefix = 0;
627 unsigned int i;
628
629 for (i = 0; i < RT_ELEMENTS(pMask->au8); ++i)
630 {
631 int iBits;
632 switch (pMask->au8[i])
633 {
634 case 0x00: iBits = 0; break;
635 case 0x80: iBits = 1; break;
636 case 0xc0: iBits = 2; break;
637 case 0xe0: iBits = 3; break;
638 case 0xf0: iBits = 4; break;
639 case 0xf8: iBits = 5; break;
640 case 0xfc: iBits = 6; break;
641 case 0xfe: iBits = 7; break;
642 case 0xff: iBits = 8; break;
643 default: /* non-contiguous mask */
644 return VERR_INVALID_PARAMETER;
645 }
646
647 iPrefix += iBits;
648 if (iBits != 8)
649 break;
650 }
651
652 for (++i; i < RT_ELEMENTS(pMask->au8); ++i)
653 if (pMask->au8[i] != 0)
654 return VERR_INVALID_PARAMETER;
655
656 if (piPrefix != NULL)
657 *piPrefix = iPrefix;
658 return VINF_SUCCESS;
659}
660RT_EXPORT_SYMBOL(RTNetMaskToPrefixIPv6);
661
662
663RTDECL(int) RTNetPrefixToMaskIPv6(int iPrefix, PRTNETADDRIPV6 pMask)
664{
665 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
666
667 if (RT_UNLIKELY(iPrefix < 0 || 128 < iPrefix))
668 return VERR_INVALID_PARAMETER;
669
670 for (unsigned int i = 0; i < RT_ELEMENTS(pMask->au32); ++i)
671 {
672 if (iPrefix == 0)
673 {
674 pMask->au32[i] = 0;
675 }
676 else if (iPrefix >= 32)
677 {
678 pMask->au32[i] = UINT32_C(0xffffffff);
679 iPrefix -= 32;
680 }
681 else
682 {
683 pMask->au32[i] = RT_H2N_U32(UINT32_C(0xffffffff) << (32 - iPrefix));
684 iPrefix = 0;
685 }
686 }
687
688 return VINF_SUCCESS;
689}
690RT_EXPORT_SYMBOL(RTNetPrefixToMaskIPv6);
691
692
693RTDECL(int) RTNetStrToIPv6Cidr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, int *piPrefix)
694{
695 RTNETADDRIPV6 Addr;
696 uint8_t u8Prefix;
697 char *pszZone, *pszNext;
698 int rc;
699
700 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
701 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
702 AssertPtrReturn(piPrefix, VERR_INVALID_PARAMETER);
703
704 pcszAddr = RTStrStripL(pcszAddr);
705 rc = rtNetStrToIPv6AddrEx(pcszAddr, &Addr, &pszZone, &pszNext);
706 if (RT_FAILURE(rc))
707 return rc;
708
709 RT_NOREF(pszZone);
710
711 /*
712 * If the prefix is missing, treat is as exact (/128) address
713 * specification.
714 */
715 if (*pszNext == '\0' || rc == VWRN_TRAILING_SPACES)
716 {
717 *pAddr = Addr;
718 *piPrefix = 128;
719 return VINF_SUCCESS;
720 }
721
722 if (*pszNext != '/')
723 return VERR_INVALID_PARAMETER;
724
725 ++pszNext;
726 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &u8Prefix);
727 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
728 return VERR_INVALID_PARAMETER;
729
730 if (u8Prefix > 128)
731 return VERR_INVALID_PARAMETER;
732
733 *pAddr = Addr;
734 *piPrefix = u8Prefix;
735 return VINF_SUCCESS;
736}
737RT_EXPORT_SYMBOL(RTNetStrToIPv6Cidr);
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use