VirtualBox

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

Last change on this file since 87203 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.6 KB
Line 
1/* $Id: netaddrstr2.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - Network Address String Handling.
4 */
5
6/*
7 * Copyright (C) 2013-2020 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/errcore.h>
36#include <iprt/mem.h>
37#include <iprt/string.h>
38#include <iprt/stream.h>
39#include "internal/string.h"
40
41
42DECLHIDDEN(int) rtNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr,
43 char **ppszNext)
44{
45 char *pszNext;
46 int rc;
47
48 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
49 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
50
51 rc = RTStrToUInt8Ex(pcszAddr, &pszNext, 10, &pAddr->au8[0]);
52 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
53 return VERR_INVALID_PARAMETER;
54 if (*pszNext++ != '.')
55 return VERR_INVALID_PARAMETER;
56
57 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[1]);
58 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
59 return VERR_INVALID_PARAMETER;
60 if (*pszNext++ != '.')
61 return VERR_INVALID_PARAMETER;
62
63 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[2]);
64 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_CHARS)
65 return VERR_INVALID_PARAMETER;
66 if (*pszNext++ != '.')
67 return VERR_INVALID_PARAMETER;
68
69 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &pAddr->au8[3]);
70 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES && rc != VWRN_TRAILING_CHARS)
71 return VERR_INVALID_PARAMETER;
72
73 if (ppszNext != NULL)
74 *ppszNext = pszNext;
75 return rc;
76}
77
78
79RTDECL(int) RTNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr,
80 char **ppszNext)
81{
82 return rtNetStrToIPv4AddrEx(pcszAddr, pAddr, ppszNext);
83}
84RT_EXPORT_SYMBOL(RTNetStrToIPv4AddrEx);
85
86
87RTDECL(int) RTNetStrToIPv4Addr(const char *pcszAddr, PRTNETADDRIPV4 pAddr)
88{
89 char *pszNext;
90 int rc;
91
92 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
93 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
94
95 pcszAddr = RTStrStripL(pcszAddr);
96 rc = rtNetStrToIPv4AddrEx(pcszAddr, pAddr, &pszNext);
97 if (RT_FAILURE(rc) || rc == VWRN_TRAILING_CHARS)
98 return VERR_INVALID_PARAMETER;
99
100 return VINF_SUCCESS;
101}
102RT_EXPORT_SYMBOL(RTNetStrToIPv4Addr);
103
104
105RTDECL(bool) RTNetIsIPv4AddrStr(const char *pcszAddr)
106{
107 RTNETADDRIPV4 addrIPv4;
108 char *pszNext;
109 int rc;
110
111 if (pcszAddr == NULL)
112 return false;
113
114 rc = rtNetStrToIPv4AddrEx(pcszAddr, &addrIPv4, &pszNext);
115 if (rc != VINF_SUCCESS)
116 return false;
117
118 if (*pszNext != '\0')
119 return false;
120
121 return true;
122}
123RT_EXPORT_SYMBOL(RTNetIsIPv4AddrStr);
124
125
126RTDECL(bool) RTNetStrIsIPv4AddrAny(const char *pcszAddr)
127{
128 RTNETADDRIPV4 addrIPv4;
129 char *pszNext;
130 int rc;
131
132 if (pcszAddr == NULL)
133 return false;
134
135 pcszAddr = RTStrStripL(pcszAddr);
136 rc = rtNetStrToIPv4AddrEx(pcszAddr, &addrIPv4, &pszNext);
137 if (RT_FAILURE(rc) || rc == VWRN_TRAILING_CHARS)
138 return false;
139
140 if (addrIPv4.u != 0u) /* INADDR_ANY? */
141 return false;
142
143 return true;
144}
145RT_EXPORT_SYMBOL(RTNetStrIsIPv4AddrAny);
146
147
148RTDECL(int) RTNetMaskToPrefixIPv4(PCRTNETADDRIPV4 pMask, int *piPrefix)
149{
150 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
151
152 if (pMask->u == 0)
153 {
154 if (piPrefix != NULL)
155 *piPrefix = 0;
156 return VINF_SUCCESS;
157 }
158
159 const uint32_t uMask = RT_N2H_U32(pMask->u);
160
161 uint32_t uPrefixMask = UINT32_C(0xffffffff);
162 int iPrefixLen = 32;
163
164 while (iPrefixLen > 0)
165 {
166 if (uMask == uPrefixMask)
167 {
168 if (piPrefix != NULL)
169 *piPrefix = iPrefixLen;
170 return VINF_SUCCESS;
171 }
172
173 --iPrefixLen;
174 uPrefixMask <<= 1;
175 }
176
177 return VERR_INVALID_PARAMETER;
178}
179RT_EXPORT_SYMBOL(RTNetMaskToPrefixIPv4);
180
181
182RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask)
183{
184 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
185
186 if (RT_UNLIKELY(iPrefix < 0 || 32 < iPrefix))
187 return VERR_INVALID_PARAMETER;
188
189 if (RT_LIKELY(iPrefix != 0))
190 pMask->u = RT_H2N_U32(UINT32_C(0xffffffff) << (32 - iPrefix));
191 else /* avoid UB in the shift */
192 pMask->u = 0;
193
194 return VINF_SUCCESS;
195}
196RT_EXPORT_SYMBOL(RTNetPrefixToMaskIPv4);
197
198
199RTDECL(int) RTNetStrToIPv4Cidr(const char *pcszAddr, PRTNETADDRIPV4 pAddr, int *piPrefix)
200{
201 RTNETADDRIPV4 Addr;
202 uint8_t u8Prefix;
203 char *pszNext;
204 int rc;
205
206 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
207 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
208 AssertPtrReturn(piPrefix, VERR_INVALID_PARAMETER);
209
210 pcszAddr = RTStrStripL(pcszAddr);
211 rc = rtNetStrToIPv4AddrEx(pcszAddr, &Addr, &pszNext);
212 if (RT_FAILURE(rc))
213 return rc;
214
215 /* if prefix is missing, treat is as exact (/32) address specification */
216 if (*pszNext == '\0' || rc == VWRN_TRAILING_SPACES)
217 {
218 *pAddr = Addr;
219 *piPrefix = 32;
220 return VINF_SUCCESS;
221 }
222
223 if (*pszNext != '/')
224 return VERR_INVALID_PARAMETER;
225
226 ++pszNext;
227 rc = RTStrToUInt8Ex(pszNext, &pszNext, 10, &u8Prefix);
228 if (RT_FAILURE(rc) || rc == VWRN_TRAILING_CHARS)
229 return VERR_INVALID_PARAMETER;
230
231 if (u8Prefix == 0 || u8Prefix > 32)
232 return VERR_INVALID_PARAMETER;
233
234 *pAddr = Addr;
235 *piPrefix = u8Prefix;
236 return VINF_SUCCESS;
237}
238RT_EXPORT_SYMBOL(RTNetStrToIPv4Cidr);
239
240
241static int rtNetStrToHexGroup(const char *pcszValue, char **ppszNext,
242 uint16_t *pu16)
243{
244 char *pszNext;
245 int rc;
246
247 rc = RTStrToUInt16Ex(pcszValue, &pszNext, 16, pu16);
248 if (RT_FAILURE(rc))
249 return rc;
250
251 if ( rc != VINF_SUCCESS
252 && rc != VWRN_TRAILING_CHARS
253 && rc != VWRN_TRAILING_SPACES)
254 {
255 return -rc; /* convert warning to error */
256 }
257
258 /* parser always accepts 0x prefix */
259 if (pcszValue[0] == '0' && (pcszValue[1] == 'x' || pcszValue[1] == 'X'))
260 {
261 if (pu16)
262 *pu16 = 0;
263 if (ppszNext)
264 *ppszNext = (/* UNCONST */ char *)pcszValue + 1; /* to 'x' */
265 return VWRN_TRAILING_CHARS;
266 }
267
268 /* parser accepts leading zeroes "000000f" */
269 if (pszNext - pcszValue > 4)
270 return VERR_PARSE_ERROR;
271
272 if (ppszNext)
273 *ppszNext = pszNext;
274 return rc;
275}
276
277
278/*
279 * This function deals only with the hex-group IPv6 address syntax
280 * proper (with possible embedded IPv4).
281 */
282DECLHIDDEN(int) rtNetStrToIPv6AddrBase(const char *pcszAddr, PRTNETADDRIPV6 pAddrResult,
283 char **ppszNext)
284{
285 RTNETADDRIPV6 ipv6;
286 RTNETADDRIPV4 ipv4;
287 const char *pcszPos;
288 char *pszNext;
289 int iGroup;
290 uint16_t u16;
291 int rc;
292
293 RT_ZERO(ipv6);
294
295 pcszPos = pcszAddr;
296
297 if (pcszPos[0] == ':') /* compressed zero run at the beginning? */
298 {
299 if (pcszPos[1] != ':')
300 return VERR_PARSE_ERROR;
301
302 pcszPos += 2; /* skip over "::" */
303 pszNext = (/* UNCONST */ char *)pcszPos;
304 iGroup = 1;
305 }
306 else
307 {
308 /*
309 * Scan forward until we either get complete address or find
310 * "::" compressed zero run.
311 */
312 pszNext = NULL; /* (MSC incorrectly thinks it may be used unitialized) */
313 for (iGroup = 0; iGroup < 8; ++iGroup)
314 {
315 /* check for embedded IPv4 at the end */
316 if (iGroup == 6)
317 {
318 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
319 if (rc == VINF_SUCCESS)
320 {
321 ipv6.au32[3] = ipv4.au32[0];
322 iGroup = 8; /* filled 6 and 7 */
323 break; /* we are done */
324 }
325 }
326
327 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
328 if (RT_FAILURE(rc))
329 return VERR_PARSE_ERROR;
330
331 ipv6.au16[iGroup] = RT_H2N_U16(u16);
332
333 if (iGroup == 7)
334 pcszPos = pszNext;
335 else
336 {
337 /* skip the colon that delimits this group */
338 if (*pszNext != ':')
339 return VERR_PARSE_ERROR;
340 pcszPos = pszNext + 1;
341
342 /* compressed zero run? */
343 if (*pcszPos == ':')
344 {
345 ++pcszPos; /* skip over :: */
346 pszNext += 2; /* skip over :: (in case we are done) */
347 iGroup += 2; /* current field and the zero in the next */
348 break;
349 }
350 }
351 }
352 }
353
354 if (iGroup != 8)
355 {
356 /*
357 * iGroup is the first group that can be filled by the part of
358 * the address after "::".
359 */
360 RTNETADDRIPV6 ipv6Tail;
361 const int iMaybeStart = iGroup;
362 int j;
363
364 RT_ZERO(ipv6Tail);
365
366 /*
367 * We try to accept longest match; we'll shift if necessary.
368 * Unlike the first loop, a failure to parse a group doesn't
369 * mean invalid address.
370 */
371 for (; iGroup < 8; ++iGroup)
372 {
373 /* check for embedded IPv4 at the end */
374 if (iGroup <= 6)
375 {
376 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
377 if (rc == VINF_SUCCESS)
378 {
379 ipv6Tail.au16[iGroup] = ipv4.au16[0];
380 ipv6Tail.au16[iGroup + 1] = ipv4.au16[1];
381 iGroup = iGroup + 2; /* these two are done */
382 break; /* the rest is trailer */
383 }
384 }
385
386 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
387 if (RT_FAILURE(rc))
388 break;
389
390 ipv6Tail.au16[iGroup] = RT_H2N_U16(u16);
391
392 if (iGroup == 7)
393 pcszPos = pszNext;
394 else
395 {
396 if (*pszNext != ':')
397 {
398 ++iGroup; /* this one is done */
399 break; /* the rest is trailer */
400 }
401
402 pcszPos = pszNext + 1;
403 }
404 }
405
406 for (j = 7, --iGroup; iGroup >= iMaybeStart; --j, --iGroup)
407 ipv6.au16[j] = ipv6Tail.au16[iGroup];
408 }
409
410 if (pAddrResult != NULL)
411 memcpy(pAddrResult, &ipv6, sizeof(ipv6));
412 if (ppszNext != NULL)
413 *ppszNext = pszNext;
414 return VINF_SUCCESS;
415}
416
417
418DECLHIDDEN(int) rtNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
419 char **ppszZone, char **ppszNext)
420{
421 char *pszNext, *pszZone;
422 int rc;
423
424 rc = rtNetStrToIPv6AddrBase(pcszAddr, pAddr, &pszNext);
425 if (RT_FAILURE(rc))
426 return rc;
427
428 if (*pszNext != '%') /* is there a zone id? */
429 {
430 pszZone = NULL;
431 }
432 else
433 {
434 pszZone = pszNext + 1; /* skip '%' zone id delimiter */
435 if (*pszZone == '\0')
436 return VERR_PARSE_ERROR; /* empty zone id */
437
438 /*
439 * XXX: this is speculative as zone id syntax is
440 * implementation dependent, so we kinda guess here (accepting
441 * unreserved characters from URI syntax).
442 */
443 for (pszNext = pszZone; *pszNext != '\0'; ++pszNext)
444 {
445 const char c = *pszNext;
446 if ( !('0' <= c && c <= '9')
447 && !('a' <= c && c <= 'z')
448 && !('A' <= c && c <= 'Z')
449 && c != '_'
450 && c != '.'
451 && c != '-'
452 && c != '~')
453 {
454 break;
455 }
456 }
457 }
458
459 if (ppszZone != NULL)
460 *ppszZone = pszZone;
461 if (ppszNext != NULL)
462 *ppszNext = pszNext;
463
464 if (*pszNext == '\0') /* all input string consumed */
465 return VINF_SUCCESS;
466 else
467 {
468 while (*pszNext == ' ' || *pszNext == '\t')
469 ++pszNext;
470 if (*pszNext == '\0')
471 return VWRN_TRAILING_SPACES;
472 else
473 return VWRN_TRAILING_CHARS;
474 }
475}
476
477
478RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
479 char **ppszNext)
480{
481 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
482 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
483
484 return rtNetStrToIPv6AddrBase(pcszAddr, pAddr, ppszNext);
485}
486RT_EXPORT_SYMBOL(RTNetStrToIPv6AddrEx);
487
488
489RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
490 char **ppszZone)
491{
492 int rc;
493
494 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
495 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
496 AssertPtrReturn(ppszZone, VERR_INVALID_PARAMETER);
497
498 pcszAddr = RTStrStripL(pcszAddr);
499 rc = rtNetStrToIPv6AddrEx(pcszAddr, pAddr, ppszZone, NULL);
500 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
501 return VERR_INVALID_PARAMETER;
502
503 return VINF_SUCCESS;
504}
505RT_EXPORT_SYMBOL(RTNetStrToIPv6Addr);
506
507
508RTDECL(bool) RTNetIsIPv6AddrStr(const char *pcszAddr)
509{
510 RTNETADDRIPV6 addrIPv6;
511 int rc;
512
513 if (pcszAddr == NULL)
514 return false;
515
516 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, NULL, NULL);
517 if (rc != VINF_SUCCESS)
518 return false;
519
520 return true;
521}
522RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr);
523
524
525RTDECL(bool) RTNetStrIsIPv6AddrAny(const char *pcszAddr)
526{
527 RTNETADDRIPV6 addrIPv6;
528 char *pszZone, *pszNext;
529 int rc;
530
531 if (pcszAddr == NULL)
532 return false;
533
534 pcszAddr = RTStrStripL(pcszAddr);
535 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, &pszZone, &pszNext);
536 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
537 return false;
538
539 if (pszZone != NULL)
540 return false;
541
542 if (addrIPv6.s.Lo != 0 || addrIPv6.s.Hi != 0) /* in6addr_any? */
543 return false;
544
545 return true;
546}
547RT_EXPORT_SYMBOL(RTNetStrIsIPv6AddrAny);
548
549
550RTDECL(int) RTNetMaskToPrefixIPv6(PCRTNETADDRIPV6 pMask, int *piPrefix)
551{
552 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
553
554 int iPrefix = 0;
555 unsigned int i;
556
557 for (i = 0; i < RT_ELEMENTS(pMask->au8); ++i)
558 {
559 int iBits;
560 switch (pMask->au8[i])
561 {
562 case 0x00: iBits = 0; break;
563 case 0x80: iBits = 1; break;
564 case 0xc0: iBits = 2; break;
565 case 0xe0: iBits = 3; break;
566 case 0xf0: iBits = 4; break;
567 case 0xf8: iBits = 5; break;
568 case 0xfc: iBits = 6; break;
569 case 0xfe: iBits = 7; break;
570 case 0xff: iBits = 8; break;
571 default: /* non-contiguous mask */
572 return VERR_INVALID_PARAMETER;
573 }
574
575 iPrefix += iBits;
576 if (iBits != 8)
577 break;
578 }
579
580 for (++i; i < RT_ELEMENTS(pMask->au8); ++i)
581 if (pMask->au8[i] != 0)
582 return VERR_INVALID_PARAMETER;
583
584 if (piPrefix != NULL)
585 *piPrefix = iPrefix;
586 return VINF_SUCCESS;
587}
588RT_EXPORT_SYMBOL(RTNetMaskToPrefixIPv6);
589
590
591RTDECL(int) RTNetPrefixToMaskIPv6(int iPrefix, PRTNETADDRIPV6 pMask)
592{
593 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
594
595 if (RT_UNLIKELY(iPrefix < 0 || 128 < iPrefix))
596 return VERR_INVALID_PARAMETER;
597
598 for (unsigned int i = 0; i < RT_ELEMENTS(pMask->au32); ++i)
599 {
600 if (iPrefix == 0)
601 {
602 pMask->au32[i] = 0;
603 }
604 else if (iPrefix >= 32)
605 {
606 pMask->au32[i] = UINT32_C(0xffffffff);
607 iPrefix -= 32;
608 }
609 else
610 {
611 pMask->au32[i] = RT_H2N_U32(UINT32_C(0xffffffff) << (32 - iPrefix));
612 iPrefix = 0;
613 }
614 }
615
616 return VINF_SUCCESS;
617}
618RT_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