source: mainline/uspace/lib/c/generic/inet/addr.c@ 5e801dc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5e801dc was ae7d03c, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Selected ccheck-proposed comment fixes.

  • Property mode set to 100644
File size: 15.4 KB
Line 
1/*
2 * Copyright (c) 2013 Jiri Svoboda
3 * Copyright (c) 2013 Martin Decky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libc
31 * @{
32 */
33/** @file Internet address parsing and formatting.
34 */
35
36#include <assert.h>
37#include <errno.h>
38#include <inet/addr.h>
39#include <stdio.h>
40#include <stddef.h>
41#include <stdlib.h>
42#include <bitops.h>
43#include <inttypes.h>
44#include <str.h>
45
46#define INET_PREFIXSTRSIZE 5
47
48#define INET6_ADDRSTRLEN (8 * 4 + 7 + 1)
49
50#if !(defined(__BE__) ^ defined(__LE__))
51#error The architecture must be either big-endian or little-endian.
52#endif
53
54const addr32_t addr32_broadcast_all_hosts = 0xffffffff;
55
56const addr48_t addr48_broadcast = {
57 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
58};
59
60static const addr48_t inet_addr48_solicited_node = {
61 0x33, 0x33, 0xff, 0, 0, 0
62};
63
64static const inet_addr_t inet_addr_any_addr = {
65 .version = ip_v4,
66 .addr = 0
67};
68
69static const inet_addr_t inet_addr_any_addr6 = {
70 .version = ip_v6,
71 .addr6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
72};
73
74void addr48(const addr48_t src, addr48_t dst)
75{
76 memcpy(dst, src, 6);
77}
78
79void addr128(const addr128_t src, addr128_t dst)
80{
81 memcpy(dst, src, 16);
82}
83
84/** Compare addr48.
85 *
86 * @return Non-zero if equal, zero if not equal.
87 */
88int addr48_compare(const addr48_t a, const addr48_t b)
89{
90 return memcmp(a, b, 6) == 0;
91}
92
93/** Compare addr128.
94 *
95 * @return Non-zero if equal, zero if not equal.
96 */
97int addr128_compare(const addr128_t a, const addr128_t b)
98{
99 return memcmp(a, b, 16) == 0;
100}
101
102/** Compute solicited node MAC multicast address from target IPv6 address
103 *
104 * @param ip Target IPv6 address
105 * @param mac Solicited MAC address to be assigned
106 *
107 */
108void addr48_solicited_node(const addr128_t ip, addr48_t mac)
109{
110 memcpy(mac, inet_addr48_solicited_node, 3);
111 memcpy(mac + 3, ip + 13, 3);
112}
113
114void host2addr128_t_be(const addr128_t host, addr128_t be)
115{
116 memcpy(be, host, 16);
117}
118
119void addr128_t_be2host(const addr128_t be, addr128_t host)
120{
121 memcpy(host, be, 16);
122}
123
124void inet_addr(inet_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
125{
126 addr->version = ip_v4;
127 addr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
128 ((addr32_t) c << 8) | ((addr32_t) d);
129}
130
131void inet_naddr(inet_naddr_t *naddr, uint8_t a, uint8_t b, uint8_t c, uint8_t d,
132 uint8_t prefix)
133{
134 naddr->version = ip_v4;
135 naddr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
136 ((addr32_t) c << 8) | ((addr32_t) d);
137 naddr->prefix = prefix;
138}
139
140void inet_addr6(inet_addr_t *addr, uint16_t a, uint16_t b, uint16_t c,
141 uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h)
142{
143 addr->version = ip_v6;
144 addr->addr6[0] = (a >> 8) & 0xff;
145 addr->addr6[1] = a & 0xff;
146 addr->addr6[2] = (b >> 8) & 0xff;
147 addr->addr6[3] = b & 0xff;
148 addr->addr6[4] = (c >> 8) & 0xff;
149 addr->addr6[5] = c & 0xff;
150 addr->addr6[6] = (d >> 8) & 0xff;
151 addr->addr6[7] = d & 0xff;
152 addr->addr6[8] = (e >> 8) & 0xff;
153 addr->addr6[9] = e & 0xff;
154 addr->addr6[10] = (f >> 8) & 0xff;
155 addr->addr6[11] = f & 0xff;
156 addr->addr6[12] = (g >> 8) & 0xff;
157 addr->addr6[13] = g & 0xff;
158 addr->addr6[14] = (h >> 8) & 0xff;
159 addr->addr6[15] = h & 0xff;
160}
161
162void inet_naddr6(inet_naddr_t *naddr, uint16_t a, uint16_t b, uint16_t c,
163 uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h, uint8_t prefix)
164{
165 naddr->version = ip_v6;
166 naddr->addr6[0] = (a >> 8) & 0xff;
167 naddr->addr6[1] = a & 0xff;
168 naddr->addr6[2] = (b >> 8) & 0xff;
169 naddr->addr6[3] = b & 0xff;
170 naddr->addr6[4] = (c >> 8) & 0xff;
171 naddr->addr6[5] = c & 0xff;
172 naddr->addr6[6] = (d >> 8) & 0xff;
173 naddr->addr6[7] = d & 0xff;
174 naddr->addr6[8] = (e >> 8) & 0xff;
175 naddr->addr6[9] = e & 0xff;
176 naddr->addr6[10] = (f >> 8) & 0xff;
177 naddr->addr6[11] = f & 0xff;
178 naddr->addr6[12] = (g >> 8) & 0xff;
179 naddr->addr6[13] = g & 0xff;
180 naddr->addr6[14] = (h >> 8) & 0xff;
181 naddr->addr6[15] = h & 0xff;
182 naddr->prefix = prefix;
183}
184
185void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr)
186{
187 addr->version = naddr->version;
188 memcpy(addr->addr6, naddr->addr6, 16);
189}
190
191void inet_addr_naddr(const inet_addr_t *addr, uint8_t prefix,
192 inet_naddr_t *naddr)
193{
194 naddr->version = addr->version;
195 memcpy(naddr->addr6, addr->addr6, 16);
196 naddr->prefix = prefix;
197}
198
199void inet_addr_any(inet_addr_t *addr)
200{
201 addr->version = ip_any;
202 memset(addr->addr6, 0, 16);
203}
204
205void inet_naddr_any(inet_naddr_t *naddr)
206{
207 naddr->version = ip_any;
208 memset(naddr->addr6, 0, 16);
209 naddr->prefix = 0;
210}
211
212int inet_addr_compare(const inet_addr_t *a, const inet_addr_t *b)
213{
214 if (a->version != b->version)
215 return 0;
216
217 switch (a->version) {
218 case ip_v4:
219 return (a->addr == b->addr);
220 case ip_v6:
221 return addr128_compare(a->addr6, b->addr6);
222 default:
223 return 0;
224 }
225}
226
227int inet_addr_is_any(const inet_addr_t *addr)
228{
229 return ((addr->version == ip_any) ||
230 (inet_addr_compare(addr, &inet_addr_any_addr)) ||
231 (inet_addr_compare(addr, &inet_addr_any_addr6)));
232}
233
234int inet_naddr_compare(const inet_naddr_t *naddr, const inet_addr_t *addr)
235{
236 if (naddr->version != addr->version)
237 return 0;
238
239 switch (naddr->version) {
240 case ip_v4:
241 return (naddr->addr == addr->addr);
242 case ip_v6:
243 return addr128_compare(naddr->addr6, addr->addr6);
244 default:
245 return 0;
246 }
247}
248
249int inet_naddr_compare_mask(const inet_naddr_t *naddr, const inet_addr_t *addr)
250{
251 if (naddr->version != addr->version)
252 return 0;
253
254 switch (naddr->version) {
255 case ip_v4:
256 if (naddr->prefix > 32)
257 return 0;
258
259 addr32_t mask =
260 BIT_RANGE(addr32_t, 31, 31 - (naddr->prefix - 1));
261 return ((naddr->addr & mask) == (addr->addr & mask));
262 case ip_v6:
263 if (naddr->prefix > 128)
264 return 0;
265
266 size_t pos = 0;
267 for (size_t i = 0; i < 16; i++) {
268 /* Further bits do not matter */
269 if (naddr->prefix < pos)
270 break;
271
272 if (naddr->prefix - pos > 8) {
273 /* Comparison without masking */
274 if (naddr->addr6[i] != addr->addr6[i])
275 return 0;
276 } else {
277 /* Comparison with masking */
278 uint8_t mask =
279 BIT_RANGE(uint8_t, 8, 8 - (naddr->prefix - pos - 1));
280 if ((naddr->addr6[i] & mask) != (addr->addr6[i] & mask))
281 return 0;
282 }
283
284 pos += 8;
285 }
286
287 return 1;
288 default:
289 return 0;
290 }
291}
292
293static errno_t inet_addr_parse_v4(const char *str, inet_addr_t *raddr,
294 int *prefix, char **endptr)
295{
296 uint32_t a = 0;
297 uint8_t b;
298 char *cur = (char *)str;
299 size_t i = 0;
300
301 while (i < 4) {
302 errno_t rc = str_uint8_t(cur, (const char **)&cur, 10, false, &b);
303 if (rc != EOK)
304 return rc;
305
306 a = (a << 8) + b;
307
308 i++;
309
310 if (*cur != '.')
311 break;
312
313 if (i < 4)
314 cur++;
315 }
316
317 if (prefix != NULL) {
318 if (*cur != '/')
319 return EINVAL;
320 cur++;
321
322 *prefix = strtoul(cur, &cur, 10);
323 if (*prefix > 32)
324 return EINVAL;
325 }
326
327 if (i != 4)
328 return EINVAL;
329
330 if (endptr == NULL && *cur != '\0')
331 return EINVAL;
332
333 raddr->version = ip_v4;
334 raddr->addr = a;
335
336 if (endptr != NULL)
337 *endptr = cur;
338
339 return EOK;
340}
341
342static errno_t inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix,
343 char **endptr)
344{
345 uint8_t data[16];
346 int explicit_groups;
347
348 memset(data, 0, 16);
349
350 const char *cur = str;
351 size_t i = 0;
352 size_t wildcard_pos = (size_t) -1;
353 size_t wildcard_size = 0;
354
355 /* Handle initial wildcard */
356 if ((str[0] == ':') && (str[1] == ':')) {
357 cur = str + 2;
358 wildcard_pos = 0;
359 wildcard_size = 16;
360 }
361
362 while (i < 16) {
363 uint16_t bioctet;
364 const char *gend;
365 errno_t rc = str_uint16_t(cur, &gend, 16, false, &bioctet);
366 if (rc != EOK)
367 break;
368
369 data[i] = (bioctet >> 8) & 0xff;
370 data[i + 1] = bioctet & 0xff;
371
372 if (wildcard_pos != (size_t) -1) {
373 if (wildcard_size < 2)
374 return EINVAL;
375
376 wildcard_size -= 2;
377 }
378
379 i += 2;
380
381 if (*gend != ':') {
382 cur = gend;
383 break;
384 }
385
386 if (i < 16) {
387 /* Handle wildcard */
388 if (gend[1] == ':') {
389 if (wildcard_pos != (size_t) -1)
390 return EINVAL;
391
392 wildcard_pos = i;
393 wildcard_size = 16 - i;
394 cur = gend + 2;
395 }
396 }
397 }
398
399 /* Number of explicitly specified groups */
400 explicit_groups = i;
401
402 if (prefix != NULL) {
403 if (*cur != '/')
404 return EINVAL;
405 cur++;
406
407 *prefix = strtoul(cur, (char **)&cur, 10);
408 if (*prefix > 128)
409 return EINVAL;
410 }
411
412 if (endptr == NULL && *cur != '\0')
413 return EINVAL;
414
415 /* Create wildcard positions */
416 if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) {
417 size_t wildcard_shift = 16 - wildcard_size;
418
419 for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) {
420 size_t j = i - 1;
421 data[j + wildcard_size] = data[j];
422 data[j] = 0;
423 }
424 } else {
425 /* Verify that all groups have been specified */
426 if (explicit_groups != 16)
427 return EINVAL;
428 }
429
430 raddr->version = ip_v6;
431 memcpy(raddr->addr6, data, 16);
432 if (endptr != NULL)
433 *endptr = (char *)cur;
434 return EOK;
435}
436
437/** Parse node address.
438 *
439 * Will fail if @a text contains extra characters at the and and @a endptr
440 * is @c NULL.
441 *
442 * @param text Network address in common notation.
443 * @param addr Place to store node address.
444 * @param endptr Place to store pointer to next character oc @c NULL
445 *
446 * @return EOK on success, EINVAL if input is not in valid format.
447 *
448 */
449errno_t inet_addr_parse(const char *text, inet_addr_t *addr, char **endptr)
450{
451 errno_t rc;
452
453 rc = inet_addr_parse_v4(text, addr, NULL, endptr);
454 if (rc == EOK)
455 return EOK;
456
457 rc = inet_addr_parse_v6(text, addr, NULL, endptr);
458 if (rc == EOK)
459 return EOK;
460
461 return EINVAL;
462}
463
464/** Parse network address.
465 *
466 * Will fail if @a text contains extra characters at the and and @a endptr
467 * is @c NULL.
468 *
469 * @param text Network address in common notation.
470 * @param naddr Place to store network address.
471 * @param endptr Place to store pointer to next character oc @c NULL
472 *
473 * @return EOK on success, EINVAL if input is not in valid format.
474 *
475 */
476errno_t inet_naddr_parse(const char *text, inet_naddr_t *naddr, char **endptr)
477{
478 errno_t rc;
479 inet_addr_t addr;
480 int prefix;
481
482 rc = inet_addr_parse_v4(text, &addr, &prefix, endptr);
483 if (rc == EOK) {
484 inet_addr_naddr(&addr, prefix, naddr);
485 return EOK;
486 }
487
488 rc = inet_addr_parse_v6(text, &addr, &prefix, endptr);
489 if (rc == EOK) {
490 inet_addr_naddr(&addr, prefix, naddr);
491 return EOK;
492 }
493
494 return EINVAL;
495}
496
497static errno_t inet_addr_format_v4(addr32_t addr, char **bufp)
498{
499 int rc;
500
501 rc = asprintf(bufp, "%u.%u.%u.%u", (addr >> 24) & 0xff,
502 (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
503 if (rc < 0)
504 return ENOMEM;
505
506 return EOK;
507}
508
509static errno_t inet_addr_format_v6(const addr128_t addr, char **bufp)
510{
511 *bufp = (char *) malloc(INET6_ADDRSTRLEN);
512 if (*bufp == NULL)
513 return ENOMEM;
514
515 /* Find the longest zero subsequence */
516
517 uint16_t zeroes[8];
518 uint16_t bioctets[8];
519
520 for (size_t i = 8; i > 0; i--) {
521 size_t j = i - 1;
522
523 bioctets[j] = (addr[j << 1] << 8) | addr[(j << 1) + 1];
524
525 if (bioctets[j] == 0) {
526 zeroes[j] = 1;
527 if (j < 7)
528 zeroes[j] += zeroes[j + 1];
529 } else
530 zeroes[j] = 0;
531 }
532
533 size_t wildcard_pos = (size_t) -1;
534 size_t wildcard_size = 0;
535
536 for (size_t i = 0; i < 8; i++) {
537 if (zeroes[i] > wildcard_size) {
538 wildcard_pos = i;
539 wildcard_size = zeroes[i];
540 }
541 }
542
543 char *cur = *bufp;
544 size_t rest = INET6_ADDRSTRLEN;
545 bool tail_zero = false;
546 int ret;
547
548 for (size_t i = 0; i < 8; i++) {
549 if ((i == wildcard_pos) && (wildcard_size > 1)) {
550 ret = snprintf(cur, rest, ":");
551 i += wildcard_size - 1;
552 tail_zero = true;
553 } else if (i == 0) {
554 ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]);
555 tail_zero = false;
556 } else {
557 ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]);
558 tail_zero = false;
559 }
560
561 if (ret < 0)
562 return EINVAL;
563
564 cur += ret;
565 rest -= ret;
566 }
567
568 if (tail_zero)
569 (void) snprintf(cur, rest, ":");
570
571 return EOK;
572}
573
574/** Format node address.
575 *
576 * @param addr Node address.
577 * @param bufp Place to store pointer to formatted string.
578 *
579 * @return EOK on success.
580 * @return ENOMEM if out of memory.
581 * @return ENOTSUP on unsupported address family.
582 *
583 */
584errno_t inet_addr_format(const inet_addr_t *addr, char **bufp)
585{
586 errno_t rc;
587 int ret;
588
589 rc = ENOTSUP;
590
591 switch (addr->version) {
592 case ip_any:
593 ret = asprintf(bufp, "none");
594 if (ret < 0)
595 return ENOMEM;
596 rc = EOK;
597 break;
598 case ip_v4:
599 rc = inet_addr_format_v4(addr->addr, bufp);
600 break;
601 case ip_v6:
602 rc = inet_addr_format_v6(addr->addr6, bufp);
603 break;
604 }
605
606 return rc;
607}
608
609/** Format network address.
610 *
611 * @param naddr Network address.
612 * @param bufp Place to store pointer to formatted string.
613 *
614 * @return EOK on success.
615 * @return ENOMEM if out of memory.
616 * @return ENOTSUP on unsupported address family.
617 *
618 */
619errno_t inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
620{
621 errno_t rc;
622 int ret;
623 char *astr;
624
625 rc = ENOTSUP;
626
627 switch (naddr->version) {
628 case ip_any:
629 ret = asprintf(bufp, "none");
630 if (ret < 0)
631 return ENOMEM;
632 rc = EOK;
633 break;
634 case ip_v4:
635 rc = inet_addr_format_v4(naddr->addr, &astr);
636 if (rc != EOK)
637 return ENOMEM;
638
639 ret = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
640 if (ret < 0) {
641 free(astr);
642 return ENOMEM;
643 }
644
645 rc = EOK;
646 break;
647 case ip_v6:
648 rc = inet_addr_format_v6(naddr->addr6, &astr);
649 if (rc != EOK)
650 return ENOMEM;
651
652 ret = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
653 if (ret < 0) {
654 free(astr);
655 return ENOMEM;
656 }
657
658 rc = EOK;
659 break;
660 }
661
662 return rc;
663}
664
665ip_ver_t inet_addr_get(const inet_addr_t *addr, addr32_t *v4, addr128_t *v6)
666{
667 switch (addr->version) {
668 case ip_v4:
669 if (v4 != NULL)
670 *v4 = addr->addr;
671 break;
672 case ip_v6:
673 if (v6 != NULL)
674 memcpy(*v6, addr->addr6, 16);
675 break;
676 default:
677 assert(false);
678 break;
679 }
680
681 return addr->version;
682}
683
684ip_ver_t inet_naddr_get(const inet_naddr_t *naddr, addr32_t *v4, addr128_t *v6,
685 uint8_t *prefix)
686{
687 switch (naddr->version) {
688 case ip_v4:
689 if (v4 != NULL)
690 *v4 = naddr->addr;
691 if (prefix != NULL)
692 *prefix = naddr->prefix;
693 break;
694 case ip_v6:
695 if (v6 != NULL)
696 memcpy(*v6, naddr->addr6, 16);
697 if (prefix != NULL)
698 *prefix = naddr->prefix;
699 break;
700 default:
701 assert(false);
702 break;
703 }
704
705 return naddr->version;
706}
707
708void inet_addr_set(addr32_t v4, inet_addr_t *addr)
709{
710 addr->version = ip_v4;
711 addr->addr = v4;
712}
713
714void inet_naddr_set(addr32_t v4, uint8_t prefix, inet_naddr_t *naddr)
715{
716 naddr->version = ip_v4;
717 naddr->addr = v4;
718 naddr->prefix = prefix;
719}
720
721void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
722{
723 addr->version = ip_v6;
724 memcpy(addr->addr6, v6, 16);
725}
726
727void inet_naddr_set6(addr128_t v6, uint8_t prefix, inet_naddr_t *naddr)
728{
729 naddr->version = ip_v6;
730 memcpy(naddr->addr6, v6, 16);
731 naddr->prefix = prefix;
732}
733
734/** @}
735 */
Note: See TracBrowser for help on using the repository browser.