VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 6 weeks ago

Copyright year updates by scm.

  • 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 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Network Address String Handling.
4 */
5
6/*
7 * Copyright (C) 2013-2024 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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette