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

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

New transport layer API. Only UDP implemented.

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