VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use