VirtualBox

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

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