1 /* $Id: ncbi_ipv6.c 598940 2019-12-17 16:10:55Z lavr $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Anton Lavrentiev
27 *
28 * File Description:
29 * IPv6 addressing support
30 *
31 */
32
33 #include "ncbi_ansi_ext.h"
34 #include "ncbi_priv.h"
35 #include <connect/ncbi_socket.h>
36 #include <connect/ncbi_ipv6.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43
44 struct SIPDNSsfx {
45 const char* sfx;
46 const size_t len;
47 };
48 static const struct SIPDNSsfx kIPv6DNS = { ".ip6.arpa", 9 };
49 static const struct SIPDNSsfx kIPv4DNS = { ".in-addr.arpa", 13 };
50
51
x_NcbiIsIPv4(const TNCBI_IPv6Addr * addr,int compat)52 static int/*bool*/ x_NcbiIsIPv4(const TNCBI_IPv6Addr* addr, int/*bool*/ compat)
53 {
54 /* RFC 4291 2.1, 3
55 NB: 2.5.5.1 and 2.5.5.2 - both obsoleted by RFC 6052 2.1 */
56 unsigned short word;
57 size_t i;
58 for (i = 0; i < 5; ++i) {
59 memcpy(&word, addr->octet + i * sizeof(word), sizeof(word));
60 if (word)
61 return 0/*false*/;
62 }
63 memcpy(&word, addr->octet + i * sizeof(word), sizeof(word));
64 if (word == 0x0000) {
65 /* IPv4-compatible IPv6 */
66 if (compat) {
67 unsigned int temp;
68 memcpy(&temp, addr->octet + sizeof(addr->octet) - sizeof(temp),
69 sizeof(temp));
70 if (SOCK_NetToHostLong(temp) & 0xFF000000)
71 return 1/*true*/;
72 }
73 return 0/*false*/;
74 }
75 /* mapped IPv4 */
76 return word == 0xFFFF ? 1/*true*/ : 0/*false*/;
77 }
78
79
NcbiIsEmptyIPv6(const TNCBI_IPv6Addr * addr)80 extern int/*bool*/ NcbiIsEmptyIPv6(const TNCBI_IPv6Addr* addr)
81 {
82 return !addr
83 || !memcchr(addr->octet, 0, sizeof(addr->octet))
84 || (x_NcbiIsIPv4(addr, 0/*mapped*/) && !NcbiIPv6ToIPv4(addr, 0))
85 ? 1/*true*/ : 0/*false*/;
86 }
87
88
NcbiIsIPv4(const TNCBI_IPv6Addr * addr)89 extern int/*bool*/ NcbiIsIPv4(const TNCBI_IPv6Addr* addr)
90 {
91 return addr && x_NcbiIsIPv4(addr, 0/*mapped*/) ? 1/*true*/ : 0/*false*/;
92 }
93
94
NcbiIsIPv4Ex(const TNCBI_IPv6Addr * addr,int compat)95 extern int/*bool*/ NcbiIsIPv4Ex(const TNCBI_IPv6Addr* addr, int/*bool*/ compat)
96 {
97 return addr && x_NcbiIsIPv4(addr, compat) ? 1/*true*/ : 0/*false*/;
98 }
99
100
NcbiIPv6ToIPv4(const TNCBI_IPv6Addr * addr,size_t pfxlen)101 extern unsigned int NcbiIPv6ToIPv4(const TNCBI_IPv6Addr* addr, size_t pfxlen)
102 {
103 unsigned int ipv4;
104 static const size_t size = sizeof(ipv4);
105 if (!addr)
106 return 0;
107 if (pfxlen == 0) {
108 if (!x_NcbiIsIPv4(addr, 1/*compat*/))
109 return 0;
110 pfxlen = 96;
111 }
112 switch (pfxlen) { /*RFC 6052 2.2*/
113 case 32:
114 memcpy( &ipv4, &addr->octet[4], size);
115 break;
116 case 40:
117 memcpy( &ipv4, &addr->octet[5], size - 1);
118 memcpy((char*) &ipv4 + size - 1, &addr->octet[9], 1);
119 break;
120 case 48:
121 memcpy( &ipv4, &addr->octet[6], size - 2);
122 memcpy((char*) &ipv4 + size - 2, &addr->octet[9], 2);
123 break;
124 case 56:
125 memcpy( &ipv4, &addr->octet[7], size - 3);
126 memcpy((char*) &ipv4 + size - 3, &addr->octet[9], 3);
127 break;
128 case 64:
129 memcpy( &ipv4, &addr->octet[9], size);
130 break;
131 case 96:
132 memcpy( &ipv4, &addr->octet[12], size);
133 break;
134 default:
135 assert(0);
136 return (unsigned int)(-1)/*failure*/;
137 }
138 return ipv4;
139 }
140
141
NcbiIPv4ToIPv6(TNCBI_IPv6Addr * addr,unsigned int ipv4,size_t pfxlen)142 extern int/*bool*/ NcbiIPv4ToIPv6(TNCBI_IPv6Addr* addr,
143 unsigned int ipv4, size_t pfxlen)
144 {
145 static const size_t size = sizeof(ipv4);
146 if (!addr)
147 return 0/*failure*/;
148 if (pfxlen == 0) {
149 /* creates IPv6 mapped */
150 memset(addr, 0, sizeof(*addr));
151 memset(addr->octet + (5 << 1), '\xFF', sizeof(unsigned short));
152 pfxlen = 96;
153 }
154 switch (pfxlen) { /*RFC 6052 2.2*/
155 case 32:
156 memcpy(&addr->octet[4], &ipv4, size);
157 break;
158 case 40:
159 memcpy(&addr->octet[5], &ipv4, size - 1);
160 memcpy(&addr->octet[9], (char*) &ipv4 + size - 1, 1);
161 break;
162 case 48:
163 memcpy(&addr->octet[6], &ipv4, size - 2);
164 memcpy(&addr->octet[9], (char*) &ipv4 + size - 2, 2);
165 break;
166 case 56:
167 memcpy(&addr->octet[7], &ipv4, size - 3);
168 memcpy(&addr->octet[9], (char*) &ipv4 + size - 3, 3);
169 break;
170 case 64:
171 memcpy(&addr->octet[9], &ipv4, size);
172 break;
173 case 96:
174 memcpy(&addr->octet[12], &ipv4, size);
175 break;
176 default:
177 assert(0);
178 return 0/*failure*/;
179 }
180 return 1/*success*/;
181 }
182
183
184 /* Parse "str" as an IP address, and return 0 if failed, otherwise a pointer to
185 * the first non-parsed char (which is neither a digit nor a dot) and "dst"
186 * updated with the just read IPv4 address in network byte order.
187 */
x_StringToIPv4(unsigned int * dst,const char * str,size_t len)188 static const char* x_StringToIPv4(unsigned int* dst,
189 const char* str, size_t len)
190 {
191 size_t n;
192 int octets = 0;
193 unsigned int tmp;
194 int/*bool*/ was_digit = 0/*false*/;
195 unsigned char *ptr = (unsigned char*) &tmp;
196
197 *ptr = 0;
198 for (n = 0; n < len; ++n) {
199 char c = str[n];
200 if ('0' <= c && c <= '9') {
201 unsigned int val;
202 if (was_digit && !*ptr)
203 return 0/*leading "0" in octet*/;
204 val = (unsigned int)(*ptr * 10 + (c - '0'));
205 if (val > 255)
206 return 0;
207 *ptr = (unsigned char) val;
208 if (!was_digit) {
209 ++octets;
210 assert(octets <= 4);
211 was_digit = 1/*true*/;
212 }
213 } else if (c == '.') {
214 if (!was_digit || octets >= 4)
215 return 0;
216 was_digit = 0/*false*/;
217 *++ptr = 0;
218 } else
219 break;
220 }
221 if (octets != 4)
222 return 0/*failure*/;
223
224 *dst = tmp;
225 return str + n;
226 }
227
228
x_IPv4ToString(char * buf,size_t bufsize,const void * src)229 static char* x_IPv4ToString(char* buf, size_t bufsize, const void* src)
230 {
231 char tmp[sizeof("255.255.255.255")];
232 unsigned char* ptr = (unsigned char*) src;
233 size_t len
234 = (size_t) sprintf(tmp, "%u.%u.%u.%u", ptr[0], ptr[1], ptr[2], ptr[3]);
235 return len < bufsize ? (char*) memcpy(buf, tmp, len + 1/*EOS*/) + len : 0;
236 }
237
238
239 /* Returns ptr past read (0 on error) */
x_StringToIPv6(TNCBI_IPv6Addr * addr,const char * str,size_t len)240 static const char* x_StringToIPv6(TNCBI_IPv6Addr* addr,
241 const char* str, size_t len)
242 {
243 unsigned short word;
244 struct {
245 const char* ptr;
246 size_t len;
247 } token[sizeof(addr->octet) / sizeof(word) + 1];
248 size_t maxt = sizeof(token) / sizeof(token[0]) - 1, t, n;
249 TNCBI_IPv6Addr temp;
250 unsigned char* dst;
251 int/*bool*/ ipv4;
252 unsigned int ip;
253 size_t gap;
254
255 if (len < 2 || (str[n = 0] == ':' && str[++n] != ':'))
256 return 0/*failure*/;
257 gap = 0;
258 ipv4 = 0/*false*/;
259 token[t = 0].ptr = str + n;
260 while (n <= len) {
261 assert(t <= maxt);
262 if (n == len || str[n] == ':') {
263 token[t].len = (size_t)(&str[n] - token[t].ptr);
264 if (token[t].len) {
265 if (n++ == len) {
266 if (++t > maxt)
267 return 0/*failure*/;
268 break;
269 }
270 } else {
271 if (n++ == len)
272 break;
273 if (gap++) /*RFC 4291 2.2, 2*/
274 return 0/*failure*/;
275 }
276 /*str[n - 1] == ':'*/
277 token[t].len++;
278 if (++t > maxt)
279 return 0/*failure*/;
280 token[t].ptr = str + n;
281 continue;
282 }
283 if (!isxdigit((unsigned char) str[n])) {
284 token[t].len = (size_t)(&str[n] - token[t].ptr);
285 if (token[t].len) {
286 if (str[n] == '.') {
287 if (t <= maxt - sizeof(ip) / sizeof(word)) {
288 const char* end
289 = x_StringToIPv4(&ip,
290 token[t].ptr,
291 token[t].len + (len - n));
292 if (end && *end != ':'
293 && t <= (maxt -= sizeof(ip) / sizeof(word))) {
294 token[t].len = (size_t)(end - token[t].ptr);
295 ipv4 = 1/*true*/;
296 break;
297 }
298 }
299 return 0/*failure*/;
300 }
301 if (++t > maxt)
302 return 0/*failure*/;
303 }
304 break;
305 }
306 n++;
307 }
308
309 assert(t <= maxt);
310 if (t < maxt && !gap)
311 return 0/*failure*/;
312
313 dst = temp.octet;
314 for (n = 0; n < t; ++n) {
315 assert(token[n].len);
316 if (*token[n].ptr != ':') {
317 char* end;
318 long val;
319 assert(isxdigit((unsigned char) token[n].ptr[0]));
320 errno = 0;
321 val = strtol(token[n].ptr, &end, 16);
322 if (errno || val ^ (val & 0xFFFF))
323 return 0/*failure*/;
324 assert(end == token[n].ptr + token[n].len - (*end == ':'));
325 if (*end == ':' && n == t - !ipv4)
326 return 0/*failure*/;
327 word = SOCK_HostToNetShort((unsigned short) val);
328 memcpy(dst, &word, sizeof(word));
329 dst += sizeof(word);
330 } else {
331 gap = (maxt - t) * sizeof(word) + sizeof(word);
332 memset(dst, 0, gap);
333 dst += gap;
334 }
335 }
336 if (ipv4) {
337 memcpy(dst, &ip, sizeof(ip));
338 ++t;
339 }
340
341 *addr = temp;
342 return token[t - 1].ptr + token[t - 1].len;
343 }
344
345
NcbiStringToIPv4(unsigned int * addr,const char * str,size_t len)346 extern const char* NcbiStringToIPv4(unsigned int* addr,
347 const char* str, size_t len)
348 {
349 size_t n;
350 if (!addr)
351 return 0/*failure*/;
352 *addr = 0;
353 if (!str)
354 return 0/*failure*/;
355 if (!len)
356 len = strlen(str);
357 for (n = 0; n < len; ++n) {
358 if (!isspace((unsigned char) str[n]))
359 break;
360 }
361 return x_StringToIPv4(addr, str + n, len - n);
362 }
363
364
NcbiStringToIPv6(TNCBI_IPv6Addr * addr,const char * str,size_t len)365 extern const char* NcbiStringToIPv6(TNCBI_IPv6Addr* addr,
366 const char* str, size_t len)
367 {
368 size_t n;
369 if (!addr)
370 return 0/*failure*/;
371 memset(addr, 0, sizeof(*addr));
372 if (!str || !*str)
373 return 0/*failure*/;
374 if (!len)
375 len = strlen(str);
376 for (n = 0; n < len; ++n) {
377 if (!isspace((unsigned char) str[n]))
378 break;
379 }
380 return x_StringToIPv6(addr, str + n, len - n);
381 }
382
383
x_IPv6ToString(char * buf,size_t bufsize,const TNCBI_IPv6Addr * addr)384 static char* x_IPv6ToString(char* buf, size_t bufsize,
385 const TNCBI_IPv6Addr* addr)
386 {
387 char ipv6[64/*enough for sizeof(8 * "xxxx:")*/];
388 char ipv4[sizeof("255.255.255.255")];
389 size_t i, n, pos, len, zpos, zlen;
390 unsigned short word;
391 char* ptr = ipv6;
392
393 if (x_NcbiIsIPv4(addr, 1/*compat*/)) {
394 unsigned int ip;
395 n = sizeof(addr->octet) - sizeof(ip);
396 memcpy(&ip, addr->octet + n, sizeof(ip));
397 SOCK_ntoa(ip, ipv4, sizeof(ipv4));
398 n /= sizeof(word);
399 } else {
400 n = sizeof(addr->octet) / sizeof(word);
401 *ipv4 = '\0';
402 }
403
404 pos = i = zpos = zlen = 0;
405 for (;;) {
406 if (i < n) {
407 memcpy(&word, &addr->octet[i * sizeof(word)], sizeof(word));
408 if (!word) {
409 ++i;
410 continue;
411 }
412 }
413 len = i - pos;
414 if (len > 1) { /*RFC 5952 4.2.2*/
415 if (zlen < len) {
416 zlen = len; /*RFC 5952 4.2.1*/
417 zpos = pos;
418 }
419 }
420 if (i == n)
421 break;
422 pos = ++i;
423 }
424
425 i = 0;
426 while (i < n) {
427 if (zlen && zpos == i) {
428 assert(zlen > 1);
429 *ptr++ = ':';
430 if (zlen == n - i)
431 *ptr++ = ':';
432 i += zlen;
433 zlen = 0; /*RFC 5952 4.2.3*/
434 continue;
435 }
436 memcpy(&word, &addr->octet[i * sizeof(word)], sizeof(word));
437 ptr += sprintf(ptr, &":%x"[!i], /*RFC 5952 4.1, 4.3*/
438 SOCK_NetToHostShort(word));
439 ++i;
440 }
441 assert(ptr > ipv6);
442
443 i = strlen(ipv4);
444 if (i) {
445 if (ptr[-1] != ':')
446 *ptr++ = ':';
447 }
448 n = (size_t)(ptr - ipv6);
449 len = n + i;
450 if (len < bufsize) {
451 memcpy(buf, ipv6, n);
452 buf += n;
453 memcpy(buf, ipv4, i);
454 buf += i;
455 *buf = '\0';
456 } else
457 buf = 0;
458 return buf;
459 }
460
461
462 /* Returns ptr past written (points to '\0'); 0 on error */
NcbiIPv4ToString(char * buf,size_t bufsize,unsigned int addr)463 extern char* NcbiIPv4ToString(char* buf, size_t bufsize,
464 unsigned int addr)
465 {
466 /* sanity */
467 if (!buf || !bufsize)
468 return 0;
469 *buf = '\0';
470
471 return x_IPv4ToString(buf, bufsize, &addr);
472 }
473
474
475 /* Returns ptr past written (points to '\0'); 0 on error */
NcbiIPv6ToString(char * buf,size_t bufsize,const TNCBI_IPv6Addr * addr)476 extern char* NcbiIPv6ToString(char* buf, size_t bufsize,
477 const TNCBI_IPv6Addr* addr)
478 {
479 /* sanity */
480 if (!buf || !bufsize)
481 return 0;
482 *buf = '\0';
483 if (!addr)
484 return 0;
485
486 return x_IPv6ToString(buf, bufsize, addr);
487 }
488
489
NcbiAddrToString(char * buf,size_t bufsize,const TNCBI_IPv6Addr * addr)490 extern char* NcbiAddrToString(char* buf, size_t bufsize,
491 const TNCBI_IPv6Addr* addr)
492 {
493 if (!buf || !bufsize)
494 return 0;
495 *buf = '\0';
496 if (!addr)
497 return 0;
498
499 if (x_NcbiIsIPv4(addr, 0/*mapped*/)) {
500 unsigned int ipv4 = NcbiIPv6ToIPv4(addr, 0);
501 return x_IPv4ToString(buf, bufsize, &ipv4);
502 }
503 return x_IPv6ToString(buf, bufsize, addr);
504 }
505
506
NcbiAddrToDNS(char * buf,size_t bufsize,const TNCBI_IPv6Addr * addr)507 extern const char* NcbiAddrToDNS(char* buf, size_t bufsize,
508 const TNCBI_IPv6Addr* addr)
509 {
510 char tmp[sizeof(addr->octet)*4 + 16/*slack*/], *dst = tmp;
511 const struct SIPDNSsfx* sfx;
512 const unsigned char* src;
513 size_t n, len;
514
515 if (!buf || !bufsize)
516 return 0;
517 *buf = '\0';
518 if (!addr)
519 return 0;
520
521 len = 0;
522 src = addr->octet + sizeof(addr->octet) - 1;
523 if (x_NcbiIsIPv4(addr, 0/*mapped*/)) {
524 sfx = &kIPv4DNS;
525 for (n = 0; n < sizeof(unsigned int); ++n) {
526 size_t off = (size_t)sprintf(dst, "%d.", *src--);
527 dst += off;
528 len += off;
529 }
530 } else {
531 sfx = &kIPv6DNS;
532 for (n = 0; n < sizeof(addr->octet); ++n) {
533 size_t off = (size_t)sprintf(dst, "%x.%x.", *src & 0xF, *src >> 4);
534 dst += off;
535 len += off;
536 --src;
537 }
538 }
539 if (len + sfx->len <= bufsize) {
540 memcpy(buf, tmp, len);
541 buf += len;
542 memcpy(buf, sfx->sfx + 1, sfx->len);
543 buf += sfx->len;
544 } else
545 buf = 0;
546 return buf;
547 }
548
549
550 /* NB: "str" is actually bounded by the ".in-addr.apra" suffix */
x_DNSToIPv4(unsigned int * addr,const char * str,size_t len)551 static const char* x_DNSToIPv4(unsigned int* addr,
552 const char* str, size_t len)
553 {
554 size_t n;
555 unsigned int temp;
556 CORE_DEBUG_ARG(const char* end = str + len;)
557 unsigned char* ptr = (unsigned char*) &temp + sizeof(temp);
558 assert(*end == '.');
559 if (len < 7/*"x.x.x.x"*/ || 15/*xxx.xxx.xxx.xxx*/ < len)
560 return 0/*failure*/;
561 for (n = 0; n < sizeof(temp); ++n) {
562 char s[4];
563 char* e;
564 long d;
565 errno = 0;
566 d = strtol(str, &e, 10); /*NB: "str" may be at "in-addr" safely here*/
567 if (errno || str == e || e - str > 3 || *e != '.'
568 || d < 0 || 255 < d
569 || sprintf(s, "%u", (unsigned int) d) != (int)(e - str)) {
570 return 0/*failure*/;
571 }
572 assert(e <= end);
573 *--ptr = (unsigned char) d;
574 str = ++e;
575 }
576 *addr = temp;
577 return --str;
578 }
579
580
581 /* NB: "str" is actually bounded by the ".ip6.arpa" suffix */
x_DNSToIPv6(TNCBI_IPv6Addr * addr,const char * str,size_t len)582 static const char* x_DNSToIPv6(TNCBI_IPv6Addr* addr,
583 const char* str, size_t len)
584 {
585 static const char xdigits[] = "0123456789abcdef";
586 CORE_DEBUG_ARG(const char* end = str + len;)
587 TNCBI_IPv6Addr temp;
588 unsigned char* dst;
589 size_t n;
590 assert(*end == '.');
591 if (len != 4 * sizeof(addr->octet) - 1)
592 return 0/*failure*/;
593 dst = temp.octet + sizeof(temp.octet) - 1;
594 for (n = 0; n < 2 * sizeof(addr->octet); ++n) {
595 const char* ptr = strchr(xdigits, tolower((unsigned char)(*str++)));
596 unsigned char val;
597 assert(str <= end);
598 if (!ptr || *str++ != '.')
599 return 0/*failure*/;
600 val = (unsigned char)(ptr - xdigits);
601 if (n & 1) {
602 val <<= 4;
603 *dst-- |= val;
604 } else
605 *dst = val;
606 }
607 *addr = temp;
608 return --str;
609 }
610
611
612 enum ENcbiIP_Form {
613 eNcbiIP_Dot = 1, /* Accept dotted notation */
614 eNcbiIP_Dns = 2 /* Accept DNS notation */
615 };
616 typedef unsigned int TNcbiIP_Form; /* Bitwise OR of ENcbiIP_Form */
617
s_StringToAddr(TNCBI_IPv6Addr * addr,const char * str,size_t len,TNcbiIP_Form how)618 static const char* s_StringToAddr(TNCBI_IPv6Addr* addr,
619 const char* str, size_t len,
620 TNcbiIP_Form how)
621 {
622 unsigned int ipv4;
623 const char* tmp;
624 size_t n;
625
626 if (!addr)
627 return 0/*failure*/;
628 memset(addr, 0, sizeof(*addr));
629 if (!str || !*str)
630 return 0/*failure*/;
631
632 if (!len)
633 len = strlen(str);
634 for (n = 0; n < len; ++n) {
635 if (!isspace((unsigned char) str[n]))
636 break;
637 }
638 str += n;
639 len -= n;
640 for (n = 0; n < len; ++n) {
641 if (!str[n] || isspace((unsigned char) str[n]))
642 break;
643 }
644 if (!(len = n))
645 return 0/*failure*/;
646
647 if (how & eNcbiIP_Dns) {
648 size_t/*bool*/ dns = str[--n] == '.' ? 1/*true*/ : 0/*false*/;
649 if (len > kIPv4DNS.len
650 && strncasecmp(tmp = str + len - (kIPv4DNS.len + dns),
651 kIPv4DNS.sfx, kIPv4DNS.len) == 0) {
652 if (x_DNSToIPv4(&ipv4, str, len - (kIPv4DNS.len + dns)) == tmp) {
653 NcbiIPv4ToIPv6(addr, ipv4, 0);
654 return tmp + (kIPv4DNS.len + dns);
655 } else if (dns)
656 return 0/*failure*/;
657 }
658 if (len > kIPv6DNS.len
659 && strncasecmp(tmp = str + len - (kIPv6DNS.len + dns),
660 kIPv6DNS.sfx, kIPv6DNS.len) == 0) {
661 if (x_DNSToIPv6(addr, str, len - (kIPv6DNS.len + dns)) == tmp)
662 return tmp + (kIPv6DNS.len + dns);
663 else if (dns)
664 return 0/*failure*/;
665 }
666 }
667 if (!(how & eNcbiIP_Dot))
668 return 0/*failure*/;
669
670 if ((tmp = x_StringToIPv4(&ipv4, str, len)) != 0) {
671 NcbiIPv4ToIPv6(addr, ipv4, 0);
672 return tmp;
673 }
674 return x_StringToIPv6(addr, str, len);
675 }
676
677
NcbiIPToAddr(TNCBI_IPv6Addr * addr,const char * str,size_t len)678 extern const char* NcbiIPToAddr(TNCBI_IPv6Addr* addr,
679 const char* str, size_t len)
680 {
681 const char* rv = s_StringToAddr(addr, str, len, eNcbiIP_Dot);
682 assert(!rv || rv > str);
683 return rv;
684 }
685
686
NcbiStringToAddr(TNCBI_IPv6Addr * addr,const char * str,size_t len)687 extern const char* NcbiStringToAddr(TNCBI_IPv6Addr* addr,
688 const char* str, size_t len)
689 {
690 const char* rv = s_StringToAddr(addr, str, len, eNcbiIP_Dns | eNcbiIP_Dot);
691 assert(!rv || rv > str);
692 return rv;
693 }
694
695
NcbiDNSIPToAddr(TNCBI_IPv6Addr * addr,const char * str,size_t len)696 extern const char* NcbiDNSIPToAddr(TNCBI_IPv6Addr* addr,
697 const char* str, size_t len)
698 {
699 const char* rv = s_StringToAddr(addr, str, len, eNcbiIP_Dns);
700 assert(!rv || rv > str);
701 return rv;
702 }
703
704
NcbiIsInIPv6Network(const TNCBI_IPv6Addr * base,unsigned int bits,const TNCBI_IPv6Addr * addr)705 extern int/*bool*/ NcbiIsInIPv6Network(const TNCBI_IPv6Addr* base,
706 unsigned int bits,
707 const TNCBI_IPv6Addr* addr)
708 {
709 size_t n;
710
711 if (!base || !addr)
712 return 0/*false*/;
713
714 if (bits > (sizeof(base->octet) << 3))
715 return 0/*false*/;
716
717 for (n = 0; n < sizeof(addr->octet); ++n) {
718 unsigned char mask;
719 if (!bits)
720 mask = 0;
721 else if (8 > bits) {
722 mask = (unsigned char)(~0 << (8 - bits));
723 bits = 0;
724 } else {
725 mask = (unsigned char)(~0);
726 bits -= 8;
727 }
728 if ((addr->octet[n] & mask) ^ base->octet[n])
729 return 0/*false*/;
730 }
731
732 return 1/*true*/;
733 }
734
735
NcbiIPv6Subnet(TNCBI_IPv6Addr * addr,unsigned int bits)736 extern int/*bool*/ NcbiIPv6Subnet(TNCBI_IPv6Addr* addr, unsigned int bits)
737 {
738 int/*bool*/ zero = 1/*true*/;
739
740 if (addr) {
741 size_t n;
742 for (n = 0; n < sizeof(addr->octet); ++n) {
743 if (!bits)
744 addr->octet[n] = 0;
745 else if (8 > bits) {
746 unsigned char mask = (unsigned char)(~0 << (8 - bits));
747 if (addr->octet[n] &= mask)
748 zero = 0/*false*/;
749 bits = 0;
750 } else {
751 bits -= 8;
752 if (addr->octet[n])
753 zero = 0/*false*/;
754 }
755 }
756 }
757
758 return !zero;
759 }
760