VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/net/netaddrstr.cpp@ 44623

Last change on this file since 44623 was 43221, checked in by vboxsync, 12 years ago

common/string/RTStrIPv6.cpp -> common/net/netaddrstr.cpp.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.2 KB
Line 
1/* $Id: netaddrstr.cpp 43221 2012-09-06 10:16:14Z vboxsync $ */
2/** @file
3 * IPRT - Network Address String Handling.
4 */
5
6/*
7 * Contributed by Oliver Loch.
8 *
9 * Copyright (C) 2012 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * The contents of this file may alternatively be used under the terms
20 * of the Common Development and Distribution License Version 1.0
21 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
22 * VirtualBox OSE distribution, in which case the provisions of the
23 * CDDL are applicable instead of those of the GPL.
24 *
25 * You may elect to license modified versions of this file under the
26 * terms and conditions of either the GPL or the CDDL or both.
27 */
28
29
30/*******************************************************************************
31* Header Files *
32*******************************************************************************/
33#include "internal/iprt.h"
34#include <iprt/net.h>
35
36#include <iprt/mem.h>
37#include <iprt/string.h>
38#include <iprt/stream.h>
39#include "internal/string.h"
40
41
42/** @page pg_rtnetipv6_addr IPv6 Address Format
43 *
44 * IPv6 Addresses, their representation in text and other problems.
45 *
46 * The following is based on:
47 *
48 * - http://tools.ietf.org/html/rfc4291
49 * - http://tools.ietf.org/html/rfc5952
50 * - http://tools.ietf.org/html/rfc6052
51 *
52 *
53 * Before you start using those functions, you should have an idea of
54 * what you're dealing with, before you come and blame the functions...
55 *
56 * First of all, the address itself:
57 *
58 * An address is written like this: (READ THIS FINE MANUAL!)
59 *
60 * - 2001:db8:abc:def::1
61 *
62 * The characters between two colons are called a "hextet".
63 * Each hextet consists of four characters and each IPv6 address
64 * consists of a maximum of eight hextets. So a full blown address
65 * would look like this:
66 *
67 * - 1111:2222:3333:4444:5555:6666:7777:8888
68 *
69 * The allowed characters are "0123456789abcdef". They have to be
70 * lower case. Upper case is not allowed.
71 *
72 * *** Gaps and adress shortening
73 *
74 * If an address contains hextets that contain only "0"s, they
75 * can be shortened, like this:
76 *
77 * - 1111:2222:0000:0000:0000:0000:7777:8888 -> 1111:2222::7777:8888
78 *
79 * The double colon represents the hextets that have been shortened "::".
80 * The "::" will be called "gap" from now on.
81 *
82 * When shortening an address, there are some special rules that need to be applied:
83 *
84 * - Shorten always the longest group of hextets.
85 *
86 * Let's say, you have this address: 2001:db8:0:0:0:1:0:0 then it has to be
87 * shortened to "2001:db8::1:0:0". Shortening to "2001:db8:0:0:0:1::" would
88 * return an error.
89 *
90 * - Two or more gaps the same size.
91 *
92 * Let's say you have this address: 2001:db8:0:0:1:0:0:1. As you can see, there
93 * are two gaps, both the size of two hextets. If you shorten the last two hextets,
94 * you end up in pain, as the RFC forbids this, so the correct address is:
95 * "2001:db8::1:0:0:1"
96 *
97 * It's important to note that an address can only be shortened ONE TIME!
98 * This is invalid: "2001:db8::1::1"
99 *
100 * *** The scope.
101 *
102 * Each address has a so called "scope" it is added to the end of the address,
103 * separated by a percent sign "%". If there is no scope at the end, it defaults
104 * to "0".
105 *
106 * So "2001:db8::1" is the same as "2001:db8::1%0".
107 *
108 * As in IPv6 all network interfaces can/should have the same address, the scope
109 * gives you the ability to choose on which interface the system should listen.
110 *
111 * AFAIK, the scope can be used with unicast as well as link local addresses, but
112 * it is mandatory with link local addresses (starting with fe80::).
113 *
114 * On Linux the default scope is the interface's name. On Windows it's just the index
115 * of the interface. Run "route print -6" in the shell, to see the interface's index
116 * on Winodows.
117 *
118 * All functions can deal with the scope, and DO NOT warn if you put garbage there.
119 *
120 * *** Port added to the IPv6 address
121 *
122 * There is only one way to add a port to an IPv6 address is to embed it in brackets:
123 *
124 * [2001:db8::1]:12345
125 *
126 * This gives you the address "2001:db8::1" and the port "12345".
127 *
128 * What also works, but is not recommended by rfc is to separate the port
129 * by a dot:
130 *
131 * 2001:db8::1.12345
132 *
133 * It even works with embedded IPv4 addresses.
134 *
135 * *** Special addresses and how they are written
136 *
137 * The following are notations to represent "special addresses".
138 *
139 * "::" IN6ADDR_ANY
140 * ":::123" IN6ADDR_ANY with port "123"
141 * "[::]:123" IN6ADDR_ANY with port "123"
142 * "[:::123]" -> NO. Not allowed and makes no sense
143 * "::1" -> address of the loopback device (127.0.0.1 in v4)
144 *
145 * On systems with dual sockets, one can use so called embedded IPv4 addresses:
146 *
147 * "::ffff:192.168.1.1" results in the IPv6 address "::ffff:c0a8:0101" as two octets
148 * of the IPv4 address will be converted to one hextet in the IPv6 address.
149 *
150 * The prefix of such addresses MUST BE "::ffff:", 10 bytes as zero and two bytes as 255.
151 *
152 * The so called IPv4-compatible IPv6 addresses are deprecated and no longer in use.
153 *
154 * *** Valid addresses and string
155 *
156 * If you use any of the IPv6 address functions, keep in mind, that those addresses
157 * are all returning "valid" even if the underlying system (e.g. VNC) doesn't like
158 * such strings.
159 *
160 * [2001:db8::1]
161 * [2001:db8::1]:12345
162 *
163 * and so on. So to make sure you only pass the underlying software a pure IPv6 address
164 * without any garbage, you should use the "outAddress" parameters to get a RFC compliant
165 * address returned.
166 *
167 * So after reading the above, you'll start using the functions and see a bool called
168 * "followRfc" which is true by default. This is what this bool does:
169 *
170 * The following addresses all represent the exact same address:
171 *
172 * 1 - 2001:db8::1
173 * 2 - 2001:db8:0::1
174 * 3 - 2001:0db8:0000:0000:0000:0000:0000:0001
175 * 4 - 2001:DB8::1
176 * 5 - [2001:db8::1]
177 * 6 - [2001:db8:0::1]
178 *
179 * According to RFC 5952, number two, three, four and six are invalid.
180 *
181 * #2 - because there is a single hextet that hasn't been shortened
182 *
183 * #3 - because there has nothing been shortened (hextets 3 to 7) and
184 * there are leading zeros in at least one hextet ("0db8")
185 *
186 * #4 - all characters in an IPv6 address have to be lower case
187 *
188 * #6 - same as two but included in brackets
189 *
190 * If you follow RFC, the above addresses are not converted and an
191 * error is returned. If you turn RFC off, you will get the expected
192 * representation of the address.
193 *
194 * It's a nice way to convert "weird" addresses to rfc compliant addresses
195 *
196 */
197
198
199/**
200 * Parses any string and tests if it is an IPv6 Address
201 *
202 * This function should NOT be used directly. If you do, note
203 * that no security checks are done at the moment. This can change.
204 *
205 * @returns iprt sstatus code.
206 * @param pszAddress The strin that holds the IPv6 address
207 * @param addressLength The length of pszAddress
208 * @param pszAddressOut Returns a plain, full blown IPv6 address
209 * as a char array
210 * @param addressOutSize The size of pszAddressOut (length)
211 * @param pPortOut 32 bit unsigned integer, holding the port
212 * If pszAddress doesn't contain a port, it's 0
213 * @param pszScopeOut Returns the scope of the address, if none it's 0
214 * @param scopeOutSize sizeof(pszScopeOut)
215 * @param pBrackets returns true if the address was enclosed in brackets
216 * @param pEmbeddedV4 returns true if the address is an embedded IPv4 address
217 * @param followRfc if set to true, the function follows RFC (default)
218 */
219static int rtStrParseAddrStr6(const char *pszAddress, size_t addressLength, char *pszAddressOut, size_t addressOutSize, uint32_t *pPortOut, char *pszIfIdOut, size_t ifIdOutSize, bool *pBrackets, bool *pEmbeddedV4, bool followRfc)
220{
221 /************************\
222 * Pointer Hell Ahead *
223 \************************/
224
225 const char szIpV6AddressChars[] = "ABCDEF01234567890abcdef.:[]%"; // order IMPORTANT
226 const char szIpV4AddressChars[] = "01234567890.:[]"; // order IMPORTANT
227 const char szLinkLocalPrefix[] = "FfEe8800"; //
228 const char *pszIpV6AddressChars = NULL, *pszIpV4AddressChars = NULL, *pszLinkLocalPrefix = NULL;
229
230 char *pszSourceAddress = NULL, *pszSourceAddressStart = NULL;
231 char *pszResultAddress = NULL, *pszResultAddressStart = NULL;
232 char *pszResultAddress4 = NULL, *pszResultAddress4Start = NULL;
233 char *pszResultPort = NULL, *pszResultPortStart = NULL;
234 char *pszInternalAddress = NULL, *pszInternalAddressStart = NULL;
235 char *pszInternalPort = NULL, *pszInternalPortStart = NULL;
236
237 char *pStart = NULL, *pNow = NULL, *pNext = NULL, *pNowChar = NULL, *pIfId = NULL, *pIfIdEnd = NULL;
238 char *pNowDigit = NULL, *pFrom = NULL, *pTo = NULL, *pLast = NULL;
239 char *pGap = NULL, *pMisc = NULL, *pDotStart = NULL, *pFieldStart = NULL, *pFieldEnd = NULL;
240 char *pFieldStartLongest = NULL, *pBracketOpen = NULL, *pBracketClose = NULL;
241 char *pszRc = NULL;
242
243 bool isLinkLocal = false;
244 char szDummy[4];
245
246 uint8_t *pByte = NULL;
247 uint32_t byteOut = 0;
248 uint16_t returnValue = 0;
249 uint32_t colons = 0;
250 uint32_t colonsOverAll = 0;
251 uint32_t fieldLength = 0;
252 uint32_t dots = 0;
253 size_t gapSize = 0;
254 uint32_t intPortOut = 0;
255
256 pszIpV4AddressChars = &szIpV4AddressChars[0];
257 pszIpV6AddressChars = &szIpV6AddressChars[6];
258 pszLinkLocalPrefix = &szLinkLocalPrefix[6];
259
260 if (!followRfc)
261 pszIpV6AddressChars = &szIpV6AddressChars[0];
262
263 if (addressLength<2)
264 returnValue = 711;
265
266 pszResultAddressStart = (char *)RTMemTmpAlloc(34);
267 pszInternalAddressStart = (char *)RTMemTmpAlloc(34);
268 pszInternalPortStart = (char * )RTMemTmpAlloc(10);
269
270 if (! (pszResultAddressStart && pszInternalAddressStart && pszInternalPortStart))
271 {
272 if (pszResultAddressStart)
273 RTMemTmpFree(pszResultAddressStart);
274
275 if (pszInternalAddressStart)
276 RTMemTmpFree(pszInternalAddressStart);
277
278 if (pszInternalPortStart)
279 RTMemTmpFree(pszInternalPortStart);
280
281 return -701;
282 }
283
284 memset(szDummy, '\0', 4);
285
286 pszResultAddress = pszResultAddressStart;
287 memset(pszResultAddressStart, '\0', 34);
288
289 pszInternalAddress = pszInternalAddressStart;
290 memset(pszInternalAddressStart, '\0' , 34);
291
292 pszInternalPort = pszInternalPortStart;
293 memset(pszInternalPortStart, '\0', 10);
294
295 pszSourceAddress = pszSourceAddressStart = (char *)pszAddress;
296
297 pFrom = pTo = pStart = pLast = pszSourceAddressStart;
298
299 while (*pszSourceAddress != '\0' && !returnValue)
300 {
301 pNow = NULL;
302 pNext = NULL;
303 pNowChar = NULL;
304 pNowDigit = NULL;
305
306 pNow = pszSourceAddress;
307 pNext = pszSourceAddress + 1;
308
309 if (!pFrom)
310 pFrom = pTo = pNow;
311
312 pNowChar = (char *)memchr(pszIpV6AddressChars, *pNow, strlen(pszIpV6AddressChars));
313 pNowDigit = (char *)memchr(pszIpV6AddressChars, *pNow, strlen(pszIpV6AddressChars) - 5);
314
315 if (pszResultPort)
316 {
317 if (pLast && (pszResultPort == pszSourceAddressStart))
318 {
319 if (*pLast == '\0')
320 returnValue = 721;
321
322 pszResultPortStart = (char *)RTMemTmpAlloc(10);
323
324 if (!pszResultPortStart)
325 returnValue = 702;
326
327 memset(pszResultPortStart, '\0', 10);
328 pszResultPort = pszResultPortStart;
329 pszSourceAddress = pLast;
330 pMisc = pLast;
331 pLast = NULL;
332 continue;
333 }
334
335 pNowDigit = NULL;
336 pNowDigit = (char *)memchr(pszIpV4AddressChars, *pNow, strlen(pszIpV4AddressChars) - 4);
337
338 if (strlen(pszResultPortStart) == 5)
339 returnValue = 11;
340
341 if (*pNow == '0' && pszResultPort == pszResultPortStart && *pNext != '\0' && (pNow - pMisc) < 5 )
342 {
343 pszSourceAddress++;
344 continue;
345 }
346
347 if (pNowDigit)
348 {
349 *pszResultPort = *pNowDigit;
350 pszResultPort++;
351 pszSourceAddress++;
352 continue;
353 }
354 else
355 returnValue = 12;
356 }
357
358 if (pszResultAddress4)
359 {
360 if (pszResultAddress4 == pszSourceAddressStart && pLast)
361 {
362 dots = 0;
363 pszResultAddress4 = NULL;
364 pszResultAddress4Start = NULL;
365 pszResultAddress4Start = (char *)RTMemTmpAlloc(20);
366
367 if (!pszResultAddress4Start)
368 {
369 returnValue = 401;
370 break;
371 }
372
373 memset(pszResultAddress4Start, '\0', 20);
374 pszResultAddress4 = pszResultAddress4Start;
375 pszSourceAddress = pLast;
376 pFrom = pLast;
377 pTo = pLast;
378 pLast = NULL;
379 continue;
380 }
381
382 pTo = pNow;
383 pNowDigit = NULL;
384 pNowDigit = (char *)memchr(pszIpV4AddressChars, *pNow, strlen(pszIpV4AddressChars) - 4);
385
386 if (!pNowDigit && *pNow != '.' && *pNow != ']' && *pNow != ':' && *pNow != '%')
387 returnValue = 412;
388
389 if ((pNow - pFrom) > 3)
390 {
391 returnValue = 402;
392 break;
393 }
394
395 if (pNowDigit && *pNext != '\0')
396 {
397 pszSourceAddress++;
398 continue;
399 }
400
401 if (!pNowDigit && !pBracketOpen && (*pNext == '.' || *pNext == ']' || *pNext == ':'))
402 returnValue = 411;
403
404 memset(pszResultAddress4, '0', 3);
405 pMisc = pszResultAddress4 + 2;
406 pszResultAddress4 = pszResultAddress4 + 3;
407
408 if (*pNow != '.' && !pNowDigit && strlen(pszResultAddress4Start) < 9)
409 returnValue = 403;
410
411 if ((pTo - pFrom) > 0)
412 pTo--;
413
414 dots++;
415
416 while (pTo >= pFrom)
417 {
418 *pMisc = *pTo;
419 pMisc--;
420 pTo--;
421 }
422
423 if (dots == 4 && *pNow == '.')
424 {
425 if (!pBracketOpen)
426 {
427 pszResultPort = pszSourceAddressStart;
428 pLast = pNext;
429 }
430 else
431 {
432 returnValue = 409;
433 }
434 }
435
436 dots = 0;
437
438 pFrom = pNext;
439 pTo = pNext;
440
441 if (strlen(pszResultAddress4Start) > 11)
442 pszResultAddress4 = NULL;
443
444 if ((*pNow == ':' || *pNow == '.') && strlen(pszResultAddress4Start) == 12)
445 {
446 pLast = pNext;
447 pszResultPort = pszSourceAddressStart;
448 }
449
450 if (*pNow == '%')
451 {
452 pIfId = pNow;
453 pLast = pNow;
454 continue;
455 }
456 pszSourceAddress = pNext;
457
458 if (*pNow != ']')
459 continue;
460
461 pFrom = pNow;
462 pTo = pNow;
463 }
464
465 if (pIfId && (!pIfIdEnd))
466 {
467 if (*pIfId == '%' && pIfId == pLast && *pNext != '\0')
468 {
469 pFrom = pNext;
470 pIfId = pNext;
471 pLast = NULL;
472
473 pszSourceAddress++;
474 continue;
475 }
476
477 if (*pNow == '%' && pIfId <= pNow)
478 {
479 returnValue = 442;
480 break;
481 }
482
483 if (*pNow != ']' && *pNext != '\0')
484 {
485 pTo = pNow;
486 pszSourceAddress++;
487 continue;
488 }
489
490 if (*pNow == ']')
491 {
492 pIfIdEnd = pNow - 1;
493 pFrom = pNow;
494 pTo = pNow;
495 continue;
496 }
497 else
498 {
499 pIfIdEnd = pNow;
500 pFrom = NULL;
501 pTo = NULL;
502 pszSourceAddress++;
503 continue;
504 }
505 }
506
507 if (!pNowChar)
508 {
509 returnValue = 254;
510
511 if (followRfc)
512 {
513 pMisc = (char *)memchr(&szIpV6AddressChars[0], *pNow, strlen(&szIpV6AddressChars[0]));
514
515 if (pMisc)
516 returnValue = 253;
517 }
518 }
519
520 if (strlen(pszResultAddressStart) > 32 && !pszResultAddress4Start)
521 returnValue = 255;
522
523 if (pNowDigit && *pNext != '\0' && colons == 0)
524 {
525 pTo = pNow;
526 pszSourceAddress++;
527 continue;
528 }
529
530 if (*pNow == ':' && *pNext != '\0')
531 {
532 colonsOverAll++;
533 colons++;
534 pszSourceAddress++;
535 continue;
536 }
537
538 if (*pNow == ':' )
539 {
540 colons++;
541 colonsOverAll++;
542 }
543
544 if (*pNow == '.')
545 {
546 pMisc = pNow;
547
548 while (*pMisc != '\0' && *pMisc != ']')
549 {
550 if (*pMisc == '.')
551 dots++;
552
553 pMisc++;
554 }
555 }
556
557 if (*pNow == ']')
558 {
559 if (pBracketClose)
560 returnValue = 77;
561
562 if (!pBracketOpen)
563 returnValue = 22;
564
565 if (*pNext == ':' || *pNext == '.')
566 {
567 pszResultPort = pszSourceAddressStart;
568 pLast = pNext + 1;
569 }
570
571 if (pFrom == pNow)
572 pFrom = NULL;
573
574 pBracketClose = pNow;
575 }
576
577 if (*pNow == '[')
578 {
579 if (pBracketOpen)
580 returnValue = 23;
581
582 if (pStart != pNow)
583 returnValue = 24;
584
585 pBracketOpen = pNow;
586 pStart++;
587 pFrom++;
588 pszSourceAddress++;
589 continue;
590 }
591
592 if (*pNow == '%')
593 {
594 if (pIfId)
595 returnValue = 441;
596
597 pLast = pNext;
598 pIfId = pNext;
599 }
600
601 if (colons > 0)
602 {
603 if (colons == 1)
604 {
605 if (pStart + 1 == pNow )
606 returnValue = 31;
607
608 if (*pNext == '\0' && !pNowDigit)
609 returnValue = 32;
610
611 pLast = pNow;
612 }
613
614 if (colons == 2)
615 {
616 if (pGap)
617 returnValue = 33;
618
619 pGap = pszResultAddress + 4;
620
621 if (pStart + 1 == pNow || pStart + 2 == pNow)
622 {
623 pGap = pszResultAddressStart;
624 pFrom = pNow;
625 }
626
627 if (*pNext == '\0' && !pNowDigit)
628 pszSourceAddress++;
629
630 if (*pNext != ':' && *pNext != '.')
631 pLast = pNow;
632 }
633
634 if (colons == 3)
635 {
636 pFrom = pLast;
637 pLast = pNow;
638
639 if (*pNext == '\0' && !pNowDigit)
640 returnValue = 34;
641
642 if (pBracketOpen)
643 returnValue = 35;
644
645 if (pGap && followRfc)
646 returnValue = 36;
647
648 if (!pGap)
649 pGap = pszResultAddress + 4;
650
651 if (pStart + 3 == pNow)
652 {
653 pszResultPort = pszSourceAddressStart;
654 pGap = pszResultAddress;
655 pFrom = NULL;
656 }
657
658 if (pNowDigit)
659 {
660 pszResultPort = pszSourceAddressStart;
661 }
662 }
663 }
664 if (*pNext == '\0' && colons == 0 && !pIfIdEnd)
665 {
666 pFrom = pLast;
667
668 if (pNowDigit)
669 pTo = pNow;
670
671 pLast = NULL;
672 }
673
674 if (dots > 0)
675 {
676 if (dots == 1)
677 {
678 pszResultPort = pszSourceAddressStart;
679 pLast = pNext;
680 }
681
682 if (dots == 4 && pBracketOpen)
683 returnValue = 601;
684
685 if (dots == 3 || dots == 4)
686 {
687 pszResultAddress4 = pszSourceAddressStart;
688 pLast = pFrom;
689 pFrom = NULL;
690 }
691
692 if (dots > 4)
693 returnValue = 603;
694
695 dots = 0;
696 }
697
698 if (pFrom && pTo)
699 {
700 if (pTo - pFrom > 3)
701 {
702 returnValue = 51;
703 break;
704 }
705
706 if (followRfc)
707 {
708 if ((pTo - pFrom > 0) && *pFrom == '0')
709 returnValue = 101;
710
711 if ((pTo - pFrom) == 0 && *pFrom == '0' && colons == 2)
712 returnValue = 102;
713
714 if ((pTo - pFrom) == 0 && *pFrom == '0' && pszResultAddress == pGap)
715 returnValue = 103;
716
717 if ((pTo - pFrom) == 0 && *pFrom == '0')
718 {
719 if (!pFieldStart)
720 {
721 pFieldStart = pszResultAddress;
722 pFieldEnd = pszResultAddress + 4;
723 }
724 else
725 {
726 pFieldEnd = pFieldEnd + 4;
727 }
728 }
729 else
730 {
731 if ((size_t)(pFieldEnd - pFieldStart) > fieldLength)
732 {
733 fieldLength = pFieldEnd - pFieldStart;
734 pFieldStartLongest = pFieldStart;
735 }
736
737 pFieldStart = NULL;
738 pFieldEnd = NULL;
739 }
740 }
741 if (!(pGap == pszResultAddressStart && (size_t)(pNow - pStart) == colons))
742 {
743 memset(pszResultAddress, '0', 4);
744 pMisc = pszResultAddress + 3;
745 pszResultAddress = pszResultAddress + 4;
746
747 if (pFrom == pStart && (pTo - pFrom) == 3)
748 {
749 isLinkLocal = true;
750
751 while (pTo >= pFrom)
752 {
753 *pMisc = *pTo;
754
755 if (*pTo != *pszLinkLocalPrefix && *pTo != *(pszLinkLocalPrefix + 1))
756 isLinkLocal = false;
757
758 pTo--;
759 pMisc--;
760 pszLinkLocalPrefix = pszLinkLocalPrefix - 2;
761 }
762 }
763 else
764 {
765 while (pTo >= pFrom)
766 {
767 *pMisc = *pTo;
768 pMisc--;
769 pTo--;
770 }
771 }
772 }
773
774 pFrom = pNow;
775 pTo = pNow;
776
777 }
778 if (*pNext == '\0' && colons == 0)
779 pszSourceAddress++;
780
781 if (*pNext == '\0' && !pBracketClose && !pszResultPort)
782 pTo = pNext;
783
784 colons = 0;
785 } // end of loop
786
787 if (!returnValue && colonsOverAll < 2)
788 returnValue = 252;
789
790 if (!returnValue && (pBracketOpen && !pBracketClose))
791 returnValue = 25;
792
793 if (!returnValue && pGap)
794 {
795 gapSize = 32 - strlen(pszResultAddressStart);
796
797 if (followRfc)
798 {
799 if (gapSize < 5)
800 returnValue = 104;
801
802 if (fieldLength > gapSize)
803 returnValue = 105;
804
805 if (fieldLength == gapSize && pFieldStartLongest < pGap)
806 returnValue = 106;
807 }
808
809 pszResultAddress = pszResultAddressStart;
810 pszInternalAddress = pszInternalAddressStart;
811
812 if (!returnValue && pszResultAddress4Start)
813 {
814 if (strlen(pszResultAddressStart) > 4)
815 returnValue = 405;
816
817 pszResultAddress = pszResultAddressStart;
818
819 if (pGap != pszResultAddressStart)
820 returnValue = 407;
821
822 memset(pszInternalAddressStart, '0', 20);
823 pszInternalAddress = pszInternalAddressStart + 20;
824
825 for (int i = 0; i < 4; i++)
826 {
827 if (*pszResultAddress != 'f' && *pszResultAddress != 'F')
828 {
829 returnValue = 406;
830 break;
831 }
832
833 *pszInternalAddress = *pszResultAddress;
834 pszResultAddress++;
835 pszInternalAddress++;
836 }
837 pszResultAddress4 = pszResultAddress4Start;
838
839 for (int i = 0; i<4; i++)
840 {
841 memcpy(szDummy, pszResultAddress4, 3);
842
843 int rc = RTStrToUInt32Ex((const char *)&szDummy[0], NULL, 16, &byteOut);
844
845 if (rc == 0 && byteOut < 256)
846 {
847 RTStrPrintf(szDummy, 3, "%02x", byteOut);
848 memcpy(pszInternalAddress, szDummy, 2);
849 pszInternalAddress = pszInternalAddress + 2;
850 pszResultAddress4 = pszResultAddress4 + 3;
851 memset(szDummy, '\0', 4);
852 }
853 else
854 {
855 returnValue = 499;
856 }
857 }
858 }
859 else
860 {
861 while (!returnValue && pszResultAddress != pGap)
862 {
863 *pszInternalAddress = *pszResultAddress;
864 pszResultAddress++;
865 pszInternalAddress++;
866 }
867
868 memset(pszInternalAddress, '0', gapSize);
869 pszInternalAddress = pszInternalAddress + gapSize;
870
871 while (!returnValue && *pszResultAddress != '\0')
872 {
873 *pszInternalAddress = *pszResultAddress;
874 pszResultAddress++;
875 pszInternalAddress++;
876 }
877 }
878 }
879 else
880 {
881 if (!returnValue)
882 {
883 if (strlen(pszResultAddressStart) != 32)
884 returnValue = 111;
885
886 if (followRfc)
887 {
888 if (fieldLength > 4)
889 returnValue = 112;
890 }
891
892 memcpy(pszInternalAddressStart, pszResultAddressStart, strlen(pszResultAddressStart));
893 }
894 }
895
896 if (pszResultPortStart)
897 {
898 if (strlen(pszResultPortStart) > 0 && strlen(pszResultPortStart) < 6)
899 {
900 memcpy(pszInternalPortStart, pszResultPortStart, strlen(pszResultPortStart));
901
902 intPortOut = 0;
903 int rc = RTStrToUInt32Ex(pszInternalPortStart, NULL, 10, &intPortOut);
904
905 if (rc == 0)
906 {
907 if (!(intPortOut > 0 && intPortOut < 65536))
908 intPortOut = 0;
909 }
910 else
911 {
912 returnValue = 888;
913 }
914 }
915 else
916 {
917 returnValue = 889;
918 }
919 }
920
921 /*
922 full blown address 32 bytes, no colons -> pszInternalAddressStart
923 port as string -> pszResultPortStart
924 port as binary integer -> intPortOut
925 interface id in pIfId and pIfIdEnd
926
927 Now fill the out parameters.
928
929 */
930
931 if (!returnValue && pszAddressOut)
932 {
933 if (strlen(pszInternalAddressStart) < addressOutSize)
934 {
935 pszRc = NULL;
936 pszRc = (char *)memset(pszAddressOut, '\0', addressOutSize);
937
938 if (!pszRc)
939 returnValue = 910;
940
941 pszRc = NULL;
942
943 pszRc = (char *)memcpy(pszAddressOut, pszInternalAddressStart, strlen(pszInternalAddressStart));
944
945 if (!pszRc)
946 returnValue = 911;
947 }
948 else
949 {
950 returnValue = 912;
951 }
952 }
953
954 if (!returnValue && pPortOut)
955 {
956 *pPortOut = intPortOut;
957 }
958
959 if (!returnValue && pszIfIdOut)
960 {
961 if (pIfIdEnd && pIfId)
962 {
963 if ((size_t)(pIfIdEnd - pIfId) + 1 < ifIdOutSize)
964 {
965 pszRc = NULL;
966 pszRc = (char *)memset(pszIfIdOut, '\0', ifIdOutSize);
967
968 if (!pszRc)
969 returnValue = 913;
970
971 pszRc = NULL;
972 pszRc = (char *)memcpy(pszIfIdOut, pIfId, (pIfIdEnd - pIfId) + 1);
973
974 if (!pszRc)
975 returnValue = 914;
976 }
977 else
978 {
979 returnValue = 915;
980 }
981 }
982 else
983 {
984 pszRc = NULL;
985 pszRc = (char *)memset(pszIfIdOut, '\0', ifIdOutSize);
986
987 if (!pszRc)
988 returnValue = 916;
989 }
990 // temporary hack
991 if (isLinkLocal && (strlen(pszIfIdOut) < 1))
992 {
993 memset(pszIfIdOut, '\0', ifIdOutSize);
994 *pszIfIdOut = '%';
995 pszIfIdOut++;
996 *pszIfIdOut = '0';
997 pszIfIdOut++;
998 }
999 }
1000
1001 if (pBracketOpen && pBracketClose && pBrackets)
1002 *pBrackets = true;
1003
1004 if (pEmbeddedV4 && pszResultAddress4Start)
1005 *pEmbeddedV4 = true;
1006
1007 if (pszResultAddressStart)
1008 RTMemTmpFree(pszResultAddressStart);
1009
1010 if (pszResultPortStart)
1011 RTMemTmpFree(pszResultPortStart);
1012
1013 if (pszResultAddress4Start)
1014 RTMemTmpFree(pszResultAddress4Start);
1015
1016 if (pszInternalAddressStart)
1017 RTMemTmpFree(pszInternalAddressStart);
1018
1019 if (pszInternalPortStart)
1020 RTMemTmpFree(pszInternalPortStart);
1021
1022 return (uint32_t)(returnValue - (returnValue * 2)); // make it negative...
1023}
1024
1025/**
1026 * Takes a string and returns a RFC compliant string of the address
1027 * This function SHOULD NOT be used directly. It expects a 33 byte
1028 * char array with a full blown IPv6 address without separators.
1029 *
1030 * @returns iprt status code.
1031 * @param psz The string to convert
1032 * @param pszAddrOut The char[] that will hold the result
1033 * @param addOutSize The size of the char[] from above.
1034 * @param pszPortOut char[] for the text representation of the port
1035 * @param portOutSize sizeof(pszPortOut);
1036 */
1037DECLHIDDEN(int) rtStrToIpAddr6Str(const char *psz, char *pszAddrOut, size_t addrOutSize, char *pszPortOut, size_t portOutSize, bool followRfc)
1038{
1039 char *pStart = NULL;
1040 char *pGapStart = NULL;
1041 char *pGapEnd = NULL;
1042 char *pGapTStart = NULL;
1043 char *pGapTEnd = NULL;
1044 char *pCurrent = NULL;
1045 char *pOut = NULL;
1046
1047 if (!psz || !pszAddrOut)
1048 return VERR_NOT_SUPPORTED;
1049
1050 if (addrOutSize < 40)
1051 return VERR_NOT_SUPPORTED;
1052
1053 pStart = (char *)psz;
1054 pCurrent = (char *)psz;
1055 pGapStart = (char *)psz;
1056 pGapEnd = (char *)psz;
1057
1058 while (*pCurrent != '\0')
1059 {
1060 if (*pCurrent != '0')
1061 pGapTStart = NULL;
1062
1063 if ((pCurrent - pStart) % 4 == 0) // ok, start of a hextet
1064 {
1065 if (*pCurrent == '0' && !pGapTStart)
1066 pGapTStart = pCurrent;
1067 }
1068
1069 if ((pCurrent - pStart) % 4 == 3)
1070 {
1071 if (*pCurrent == '0' && pGapTStart)
1072 pGapTEnd = pCurrent;
1073
1074 if (pGapTStart && pGapTEnd)
1075 {
1076 pGapTEnd = pCurrent;
1077
1078 if ((pGapTEnd - pGapTStart) > (pGapEnd - pGapStart))
1079 {
1080 pGapEnd = pGapTEnd;
1081 pGapStart = pGapTStart;
1082 }
1083 }
1084 }
1085
1086 pCurrent++;
1087 }
1088
1089 pCurrent = (char *)psz;
1090 pStart = (char *)psz;
1091 pOut = (char *)pszAddrOut;
1092
1093 while (*pCurrent != '\0')
1094 {
1095 if (*pCurrent != '0')
1096 pGapTStart = NULL;
1097
1098 if (!pGapTStart)
1099 {
1100 *pOut = *pCurrent;
1101 pOut++;
1102 }
1103
1104 if ((pCurrent - pStart) % 4 == 3)
1105 {
1106 if (pGapTStart && *pCurrent == '0')
1107 {
1108 *pOut = *pCurrent;
1109 pOut++;
1110 }
1111
1112 if (*(pCurrent + 1) != '\0')
1113 {
1114 *pOut = ':';
1115 pOut++;
1116 }
1117
1118 pGapTStart = pCurrent + 1;
1119 }
1120
1121 if ((pCurrent + 1) == pGapStart && (pGapEnd - pGapStart) > 3)
1122 {
1123 *pOut = ':';
1124 pOut++;
1125 pCurrent = pGapEnd;
1126 }
1127
1128 pCurrent++;
1129 }
1130
1131 return VINF_SUCCESS;
1132}
1133
1134
1135/**
1136 * Tests if the given string is a valid IPv6 address.
1137 *
1138 * @returns 0 if valid, some random number if not. THIS IS NOT AN IPRT STATUS!
1139 * @param psz The string to test
1140 * @param pszResultAddress plain address, optional read "valid addresses
1141 * and strings" above.
1142 * @param resultAddressSize size of pszResultAddress
1143 * @param addressOnly return only the plain address (no scope)
1144 * Ignored, and will always return the if id
1145 */
1146static int rtNetIpv6CheckAddrStr(const char *psz, char *pszResultAddress, size_t resultAddressSize, bool addressOnly, bool followRfc)
1147{
1148 int rc;
1149 int rc2;
1150 int returnValue;
1151
1152 char *p = NULL, *pl = NULL;
1153
1154 size_t memAllocMaxSize = RT_MAX(strlen(psz), resultAddressSize) + 40;
1155
1156 char *pszAddressOutLocal = (char *)RTMemTmpAlloc(memAllocMaxSize);
1157 char *pszIfIdOutLocal = (char *)RTMemTmpAlloc(memAllocMaxSize);
1158 char *pszAddressRfcOutLocal = (char *)RTMemTmpAlloc(memAllocMaxSize);
1159
1160 if (!pszAddressOutLocal || !pszIfIdOutLocal || !pszAddressRfcOutLocal)
1161 return VERR_NO_TMP_MEMORY;
1162
1163 memset(pszAddressOutLocal, '\0', memAllocMaxSize);
1164 memset(pszIfIdOutLocal, '\0', memAllocMaxSize);
1165 memset(pszAddressRfcOutLocal, '\0', memAllocMaxSize);
1166
1167 rc = rtStrParseAddrStr6(psz, strlen(psz), pszAddressOutLocal, memAllocMaxSize, NULL, pszIfIdOutLocal, memAllocMaxSize, NULL, NULL, followRfc);
1168
1169 if (rc == 0)
1170 returnValue = VINF_SUCCESS;
1171
1172 if (rc == 0 && pszResultAddress)
1173 {
1174 // convert the 32 characters to a valid, shortened ipv6 address
1175
1176 rc2 = rtStrToIpAddr6Str((const char *)pszAddressOutLocal, pszAddressRfcOutLocal, memAllocMaxSize, NULL, 0, followRfc);
1177
1178 if (rc2 != 0)
1179 returnValue = 951;
1180
1181 // this is a temporary solution
1182 if (!returnValue && strlen(pszIfIdOutLocal) > 0) // the if identifier is copied over _ALWAYS_ && !addressOnly)
1183 {
1184 p = pszAddressRfcOutLocal + strlen(pszAddressRfcOutLocal);
1185
1186 *p = '%';
1187
1188 p++;
1189
1190 pl = (char *)memcpy(p, pszIfIdOutLocal, strlen(pszIfIdOutLocal));
1191
1192 if (!pl)
1193 returnValue = VERR_NOT_SUPPORTED;
1194 }
1195
1196 pl = NULL;
1197
1198 pl = (char *)memcpy(pszResultAddress, pszAddressRfcOutLocal, strlen(pszAddressRfcOutLocal));
1199
1200 if (!pl)
1201 returnValue = VERR_NOT_SUPPORTED;
1202 }
1203
1204 if (rc != 0)
1205 returnValue = VERR_NOT_SUPPORTED;
1206
1207 if (pszAddressOutLocal)
1208 RTMemTmpFree(pszAddressOutLocal);
1209
1210 if (pszAddressRfcOutLocal)
1211 RTMemTmpFree(pszAddressRfcOutLocal);
1212
1213 if (pszIfIdOutLocal)
1214 RTMemTmpFree(pszIfIdOutLocal);
1215
1216 return returnValue;
1217
1218}
1219
1220
1221RTDECL(bool) RTNetIsIPv6AddrStr(const char *pszAddress)
1222{
1223 return rtNetIpv6CheckAddrStr(pszAddress, NULL, 0, true, true) >= 0;
1224}
1225RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr);
1226
1227
1228RTDECL(bool) RTNetIsIPv4AddrStr(const char *pszAddress)
1229{
1230 static char const s_szIpV4Digits[] = "0123456789.";
1231
1232 size_t cchAddress = strlen(pszAddress);
1233 if (cchAddress < 7 || cchAddress > 15)
1234 return false;
1235
1236 const char *pStart, *pFrom, *pTo, *pNow;
1237 pStart = pNow = pFrom = pTo = pszAddress;
1238
1239 unsigned cOctets = 0;
1240 while (*pNow != '\0')
1241 {
1242 const char *pChar = (const char *)memchr(s_szIpV4Digits, *pNow, sizeof(s_szIpV4Digits) - 1);
1243 const char *pDigit = (const char *)memchr(s_szIpV4Digits, *pNow, sizeof(s_szIpV4Digits) - 2);
1244 const char *pNext = pNow + 1;
1245
1246 if (!pChar)
1247 return false;
1248
1249 if (pDigit && *pNext != '\0')
1250 {
1251 pTo = pNow;
1252 pNow++;
1253 continue;
1254 }
1255
1256 if (*pNow == '.' || *pNext == '\0')
1257 {
1258 if (*pNext == '\0')
1259 pTo = pNow;
1260
1261 size_t cchSub = pTo - pFrom;
1262 if (cchSub > 2)
1263 return false;
1264
1265 char szDummy[4] = { 0, 0, 0, 0 };
1266 memcpy(szDummy, pFrom, cchSub + 1);
1267
1268 int rc = RTStrToUInt8Ex(szDummy, NULL, 10, NULL);
1269 if (rc != VINF_SUCCESS)
1270 return false;
1271
1272 cOctets++;
1273 if (cOctets > 4)
1274 return false;
1275 pFrom = pNext;
1276 }
1277 pNow++;
1278 }
1279
1280 if (cOctets != 4)
1281 return false;
1282
1283 return true;
1284}
1285RT_EXPORT_SYMBOL(RTNetIsIPv4AddrStr);
1286
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