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

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

dnsr_name2host should use ip_ver_t instead of AF.

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