VirtualBox

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

Last change on this file since 57358 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1/* $Id: netaddrstr2.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * IPRT - Network Address String Handling.
4 */
5
6/*
7 * Copyright (C) 2013-2015 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
129static int rtNetStrToHexGroup(const char *pcszValue, char **ppszNext,
130 uint16_t *pu16)
131{
132 char *pszNext;
133 int rc;
134
135 rc = RTStrToUInt16Ex(pcszValue, &pszNext, 16, pu16);
136 if (RT_FAILURE(rc))
137 return rc;
138
139 if ( rc != VINF_SUCCESS
140 && rc != VWRN_TRAILING_CHARS
141 && rc != VWRN_TRAILING_SPACES)
142 {
143 return -rc; /* convert warning to error */
144 }
145
146 /* parser always accepts 0x prefix */
147 if (pcszValue[0] == '0' && (pcszValue[1] == 'x' || pcszValue[1] == 'X'))
148 {
149 if (pu16)
150 *pu16 = 0;
151 if (ppszNext)
152 *ppszNext = (/* UNCONST */ char *)pcszValue + 1; /* to 'x' */
153 return VWRN_TRAILING_CHARS;
154 }
155
156 /* parser accepts leading zeroes "000000f" */
157 if (pszNext - pcszValue > 4)
158 return VERR_PARSE_ERROR;
159
160 if (ppszNext)
161 *ppszNext = pszNext;
162 return rc;
163}
164
165
166/*
167 * This function deals only with the hex-group IPv6 address syntax
168 * proper (with possible embedded IPv4).
169 */
170DECLHIDDEN(int) rtNetStrToIPv6AddrBase(const char *pcszAddr, PRTNETADDRIPV6 pAddrResult,
171 char **ppszNext)
172{
173 RTNETADDRIPV6 ipv6;
174 RTNETADDRIPV4 ipv4;
175 const char *pcszPos;
176 char *pszNext;
177 int iGroup;
178 uint16_t u16;
179 int rc;
180
181 memset(&ipv6, 0, sizeof(ipv6));
182
183 pcszPos = pcszAddr;
184
185 if (pcszPos[0] == ':') /* compressed zero run at the beginning? */
186 {
187 if (pcszPos[1] != ':')
188 return VERR_PARSE_ERROR;
189
190 pcszPos += 2; /* skip over "::" */
191 pszNext = (/* UNCONST */ char *)pcszPos;
192 iGroup = 1;
193 }
194 else
195 {
196 /*
197 * Scan forward until we either get complete address or find
198 * "::" compressed zero run.
199 */
200 for (iGroup = 0; iGroup < 8; ++iGroup)
201 {
202 /* check for embedded IPv4 at the end */
203 if (iGroup == 6)
204 {
205 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
206 if (rc == VINF_SUCCESS)
207 {
208 ipv6.au32[3] = ipv4.au32[0];
209 iGroup = 8; /* filled 6 and 7 */
210 break; /* we are done */
211 }
212 }
213
214 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
215 if (RT_FAILURE(rc))
216 return VERR_PARSE_ERROR;
217
218 ipv6.au16[iGroup] = RT_H2N_U16(u16);
219
220 if (iGroup == 7)
221 pcszPos = pszNext;
222 else
223 {
224 /* skip the colon that delimits this group */
225 if (*pszNext != ':')
226 return VERR_PARSE_ERROR;
227 pcszPos = pszNext + 1;
228
229 /* compressed zero run? */
230 if (*pcszPos == ':')
231 {
232 ++pcszPos; /* skip over :: */
233 pszNext += 2; /* skip over :: (in case we are done) */
234 iGroup += 2; /* current field and the zero in the next */
235 break;
236 }
237 }
238 }
239 }
240
241 if (iGroup != 8)
242 {
243 /*
244 * iGroup is the first group that can be filled by the part of
245 * the address after "::".
246 */
247 RTNETADDRIPV6 ipv6Tail;
248 const int iMaybeStart = iGroup;
249 int j;
250
251 memset(&ipv6Tail, 0, sizeof(ipv6Tail));
252
253 /*
254 * We try to accept longest match; we'll shift if necessary.
255 * Unlike the first loop, a failure to parse a group doesn't
256 * mean invalid address.
257 */
258 for (; iGroup < 8; ++iGroup)
259 {
260 /* check for embedded IPv4 at the end */
261 if (iGroup <= 6)
262 {
263 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext);
264 if (rc == VINF_SUCCESS)
265 {
266 ipv6Tail.au16[iGroup] = ipv4.au16[0];
267 ipv6Tail.au16[iGroup + 1] = ipv4.au16[1];
268 iGroup = iGroup + 2; /* these two are done */
269 break; /* the rest is trailer */
270 }
271 }
272
273 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16);
274 if (RT_FAILURE(rc))
275 break;
276
277 ipv6Tail.au16[iGroup] = RT_H2N_U16(u16);
278
279 if (iGroup == 7)
280 pcszPos = pszNext;
281 else
282 {
283 if (*pszNext != ':')
284 {
285 ++iGroup; /* this one is done */
286 break; /* the rest is trailer */
287 }
288
289 pcszPos = pszNext + 1;
290 }
291 }
292
293 for (j = 7, --iGroup; iGroup >= iMaybeStart; --j, --iGroup)
294 ipv6.au16[j] = ipv6Tail.au16[iGroup];
295 }
296
297 if (pAddrResult != NULL)
298 memcpy(pAddrResult, &ipv6, sizeof(ipv6));
299 if (ppszNext != NULL)
300 *ppszNext = pszNext;
301 return VINF_SUCCESS;
302}
303
304
305DECLHIDDEN(int) rtNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
306 char **ppszZone, char **ppszNext)
307{
308 char *pszNext, *pszZone;
309 int rc;
310
311 rc = rtNetStrToIPv6AddrBase(pcszAddr, pAddr, &pszNext);
312 if (RT_FAILURE(rc))
313 return rc;
314
315 if (*pszNext != '%') /* is there a zone id? */
316 {
317 pszZone = NULL;
318 }
319 else
320 {
321 pszZone = pszNext + 1; /* skip '%' zone id delimiter */
322 if (*pszZone == '\0')
323 return VERR_PARSE_ERROR; /* empty zone id */
324
325 /*
326 * XXX: this is speculative as zone id syntax is
327 * implementation dependent, so we kinda guess here (accepting
328 * unreserved characters from URI syntax).
329 */
330 for (pszNext = pszZone; *pszNext != '\0'; ++pszNext)
331 {
332 const char c = *pszNext;
333 if ( !('0' <= c && c <= '9')
334 && !('a' <= c && c <= 'z')
335 && !('A' <= c && c <= 'Z')
336 && c != '_'
337 && c != '.'
338 && c != '-'
339 && c != '~')
340 {
341 break;
342 }
343 }
344 }
345
346 if (ppszZone != NULL)
347 *ppszZone = pszZone;
348 if (ppszNext != NULL)
349 *ppszNext = pszNext;
350
351 if (*pszNext == '\0') /* all input string consumed */
352 return VINF_SUCCESS;
353 else
354 {
355 while (*pszNext == ' ' || *pszNext == '\t')
356 ++pszNext;
357 if (*pszNext == '\0')
358 return VWRN_TRAILING_SPACES;
359 else
360 return VWRN_TRAILING_CHARS;
361 }
362}
363
364
365RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
366 char **ppszNext)
367{
368 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
369 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
370
371 return rtNetStrToIPv6AddrBase(pcszAddr, pAddr, ppszNext);
372}
373RT_EXPORT_SYMBOL(RTNetStrToIPv6AddrEx);
374
375
376RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr,
377 char **ppszZone)
378{
379 int rc;
380
381 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER);
382 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER);
383 AssertPtrReturn(ppszZone, VERR_INVALID_PARAMETER);
384
385 pcszAddr = RTStrStripL(pcszAddr);
386 rc = rtNetStrToIPv6AddrEx(pcszAddr, pAddr, ppszZone, NULL);
387 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES)
388 return VERR_INVALID_PARAMETER;
389
390 return VINF_SUCCESS;
391}
392RT_EXPORT_SYMBOL(RTNetStrToIPv6Addr);
393
394
395RTDECL(bool) RTNetIsIPv6AddrStr(const char *pcszAddr)
396{
397 RTNETADDRIPV6 addrIPv6;
398 int rc;
399
400 if (pcszAddr == NULL)
401 return false;
402
403 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, NULL, NULL);
404 if (rc != VINF_SUCCESS)
405 return false;
406
407 return true;
408}
409RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr);
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