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

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

Fix bug in address parsing (thx Jan Buchar)

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