VirtualBox

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

最後變更 在這個檔案從65579是 65579,由 vboxsync 提交於 8 年 前

IPRT: RTNetMaskToPrefixIPv4 and RTNetPrefixToMaskIPv4.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 13.8 KB
 
1/* $Id: netaddrstr2.cpp 65579 2017-02-01 21:32:38Z vboxsync $ */
2/** @file
3 * IPRT - Network Address String Handling.
4 */
5
6/*
7 * Copyright (C) 2013-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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 if (uMask == uPrefixMask)
173 {
174 if (piPrefix != NULL)
175 *piPrefix = iPrefixLen;
176 return VINF_SUCCESS;
177 }
178
179 --iPrefixLen;
180 uPrefixMask <<= 1;
181 }
182
183 return VERR_INVALID_PARAMETER;
184}
185RT_EXPORT_SYMBOL(RTNetMaskToPrefixIPv4);
186
187
188RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask)
189{
190 AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
191
192 if (RT_UNLIKELY(iPrefix < 0 || 32 < iPrefix))
193 return VERR_INVALID_PARAMETER;
194
195 if (RT_LIKELY(iPrefix != 0))
196 pMask->u = RT_H2N_U32(UINT32_C(0xffffffff) << (32 - iPrefix));
197 else /* avoid UB in the shift */
198 pMask->u = 0;
199
200 return VINF_SUCCESS;
201}
202RT_EXPORT_SYMBOL(RTNetPrefixToMaskIPv4);
203
204
205static int rtNetStrToHexGroup(const char *pcszValue, char **ppszNext,
206 uint16_t *pu16)
207{
208 char *pszNext;
209 int rc;
210
211 rc = RTStrToUInt16Ex(pcszValue, &pszNext, 16, pu16);
212 if (RT_FAILURE(rc))
213 return rc;
214
215 if ( rc != VINF_SUCCESS
216 && rc != VWRN_TRAILING_CHARS
217 && rc != VWRN_TRAILING_SPACES)
218 {
219 return -rc; /* convert warning to error */
220 }
221
222 /* parser always accepts 0x prefix */
223 if (pcszValue[0] == '0' && (pcszValue[1] == 'x' || pcszValue[1] == 'X'))
224 {
225 if (pu16)
226 *pu16 = 0;
227 if (ppszNext)
228 *ppszNext = (/* UNCONST */ char *)pcszValue + 1; /* to 'x' */
229 return VWRN_TRAILING_CHARS;
230 }
231
232 /* parser accepts leading zeroes "000000f" */
233 if (pszNext - pcszValue > 4)
234 return VERR_PARSE_ERROR;
235
236 if (ppszNext)
237 *ppszNext = pszNext;
238 return rc;
239}
240
241
242/*
243 * This function deals only with the hex-group IPv6 address syntax
244 * proper (with possible embedded IPv4).
245 */
246DECLHIDDEN(int) rtNetStrToIPv6AddrBase(const char *pcszAddr, PRTNETADDRIPV6 pAddrResult,
247 char **ppszNext)
248{
249 RTNETADDRIPV6 ipv6;
250 RTNETADDRIPV4 ipv4;
251 const char *pcszPos;
252 char *pszNext;
253 int iGroup;
254 uint16_t u16;
255 int rc;
256
257 memset(&ipv6, 0, sizeof(ipv6));
258
259 pcszPos = pcszAddr;
260
261 if (pcszPos[0] == ':') /* compressed zero run at the beginning? */
262 {
263 if (pcszPos[1] != ':')
264 return VERR_PARSE_ERROR;
265
266 pcszPos += 2; /* skip over "::" */
267 pszNext = (/* UNCONST */ char *)pcszPos;
268 iGroup = 1;
269 }
270 else
271 {
272 /*
273 * Scan forward until we either get complete address or find
274 * "::" compressed zero run.
275 */
276 pszNext = NULL; /* (MSC incorrectly thinks it may be used unitialized) */
277 for (iGroup = 0; iGroup < 8; ++iGroup)
278 {
279 /* check for embedded IPv4 at the end */
280 if (iGroup == 6)
281 {
282 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
283 if (rc == VINF_SUCCESS)
284 {
285 ipv6.au32[3] = ipv4.au32[0];
286 iGroup = 8; /* filled 6 and 7 */
287 break; /* we are done */
288 }
289 }
290
291 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
292 if (RT_FAILURE(rc))
293 return VERR_PARSE_ERROR;
294
295 ipv6.au16[iGroup] = RT_H2N_U16(u16);
296
297 if (iGroup == 7)
298 pcszPos = pszNext;
299 else
300 {
301 /* skip the colon that delimits this group */
302 if (*pszNext != ':')
303 return VERR_PARSE_ERROR;
304 pcszPos = pszNext + 1;
305
306 /* compressed zero run? */
307 if (*pcszPos == ':')
308 {
309 ++pcszPos; /* skip over :: */
310 pszNext += 2; /* skip over :: (in case we are done) */
311 iGroup += 2; /* current field and the zero in the next */
312 break;
313 }
314 }
315 }
316 }
317
318 if (iGroup != 8)
319 {
320 /*
321 * iGroup is the first group that can be filled by the part of
322 * the address after "::".
323 */
324 RTNETADDRIPV6 ipv6Tail;
325 const int iMaybeStart = iGroup;
326 int j;
327
328 memset(&ipv6Tail, 0, sizeof(ipv6Tail));
329
330 /*
331 * We try to accept longest match; we'll shift if necessary.
332 * Unlike the first loop, a failure to parse a group doesn't
333 * mean invalid address.
334 */
335 for (; iGroup < 8; ++iGroup)
336 {
337 /* check for embedded IPv4 at the end */
338 if (iGroup <= 6)
339 {
340 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
341 if (rc == VINF_SUCCESS)
342 {
343 ipv6Tail.au16[iGroup] = ipv4.au16[0];
344 ipv6Tail.au16[iGroup + 1] = ipv4.au16[1];
345 iGroup = iGroup + 2; /* these two are done */
346 break; /* the rest is trailer */
347 }
348 }
349
350 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
351 if (RT_FAILURE(rc))
352 break;
353
354 ipv6Tail.au16[iGroup] = RT_H2N_U16(u16);
355
356 if (iGroup == 7)
357 pcszPos = pszNext;
358 else
359 {
360 if (*pszNext != ':')
361 {
362 ++iGroup; /* this one is done */
363 break; /* the rest is trailer */
364 }
365
366 pcszPos = pszNext + 1;
367 }
368 }
369
370 for (j = 7, --iGroup; iGroup >= iMaybeStart; --j, --iGroup)
371 ipv6.au16[j] = ipv6Tail.au16[iGroup];
372 }
373
374 if (pAddrResult != NULL)
375 memcpy(pAddrResult, &ipv6, sizeof(ipv6));
376 if (ppszNext != NULL)
377 *ppszNext = pszNext;
378 return VINF_SUCCESS;
379}
380
381
382DECLHIDDEN(int) rtNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
383 char **ppszZone, char **ppszNext)
384{
385 char *pszNext, *pszZone;
386 int rc;
387
388 rc = rtNetStrToIPv6AddrBase(pcszAddr, pAddr, &pszNext);
389 if (RT_FAILURE(rc))
390 return rc;
391
392 if (*pszNext != '%') /* is there a zone id? */
393 {
394 pszZone = NULL;
395 }
396 else
397 {
398 pszZone = pszNext + 1; /* skip '%' zone id delimiter */
399 if (*pszZone == '\0')
400 return VERR_PARSE_ERROR; /* empty zone id */
401
402 /*
403 * XXX: this is speculative as zone id syntax is
404 * implementation dependent, so we kinda guess here (accepting
405 * unreserved characters from URI syntax).
406 */
407 for (pszNext = pszZone; *pszNext != '\0'; ++pszNext)
408 {
409 const char c = *pszNext;
410 if ( !('0' <= c && c <= '9')
411 && !('a' <= c && c <= 'z')
412 && !('A' <= c && c <= 'Z')
413 && c != '_'
414 && c != '.'
415 && c != '-'
416 && c != '~')
417 {
418 break;
419 }
420 }
421 }
422
423 if (ppszZone != NULL)
424 *ppszZone = pszZone;
425 if (ppszNext != NULL)
426 *ppszNext = pszNext;
427
428 if (*pszNext == '\0') /* all input string consumed */
429 return VINF_SUCCESS;
430 else
431 {
432 while (*pszNext == ' ' || *pszNext == '\t')
433 ++pszNext;
434 if (*pszNext == '\0')
435 return VWRN_TRAILING_SPACES;
436 else
437 return VWRN_TRAILING_CHARS;
438 }
439}
440
441
442RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
443 char **ppszNext)
444{
445 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
446 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
447
448 return rtNetStrToIPv6AddrBase(pcszAddr, pAddr, ppszNext);
449}
450RT_EXPORT_SYMBOL(RTNetStrToIPv6AddrEx);
451
452
453RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
454 char **ppszZone)
455{
456 int rc;
457
458 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
459 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
460 AssertPtrReturn(ppszZone, VERR_INVALID_PARAMETER);
461
462 pcszAddr = RTStrStripL(pcszAddr);
463 rc = rtNetStrToIPv6AddrEx(pcszAddr, pAddr, ppszZone, NULL);
464 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
465 return VERR_INVALID_PARAMETER;
466
467 return VINF_SUCCESS;
468}
469RT_EXPORT_SYMBOL(RTNetStrToIPv6Addr);
470
471
472RTDECL(bool) RTNetIsIPv6AddrStr(const char *pcszAddr)
473{
474 RTNETADDRIPV6 addrIPv6;
475 int rc;
476
477 if (pcszAddr == NULL)
478 return false;
479
480 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, NULL, NULL);
481 if (rc != VINF_SUCCESS)
482 return false;
483
484 return true;
485}
486RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr);
487
488
489RTDECL(bool) RTNetStrIsIPv6AddrAny(const char *pcszAddr)
490{
491 RTNETADDRIPV6 addrIPv6;
492 char *pszZone, *pszNext;
493 int rc;
494
495 if (pcszAddr == NULL)
496 return false;
497
498 pcszAddr = RTStrStripL(pcszAddr);
499 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, &pszZone, &pszNext);
500 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
501 return false;
502
503 if (pszZone != NULL)
504 return false;
505
506 if (addrIPv6.s.Lo != 0 || addrIPv6.s.Hi != 0) /* in6addr_any? */
507 return false;
508
509 return true;
510}
511RT_EXPORT_SYMBOL(RTNetStrIsIPv6AddrAny);
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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