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

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

HelenOS internet address version should not be based on BSD sockets definition.

  • Property mode set to 100644
File size: 14.2 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
252void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr)
253{
254 addr->version = naddr->version;
255 memcpy(addr->addr6, naddr->addr6, 16);
256}
257
258void inet_addr_naddr(const inet_addr_t *addr, uint8_t prefix,
259 inet_naddr_t *naddr)
260{
261 naddr->version = addr->version;
262 memcpy(naddr->addr6, addr->addr6, 16);
263 naddr->prefix = prefix;
264}
265
266void inet_addr_any(inet_addr_t *addr)
267{
268 addr->version = ip_any;
269 memset(addr->addr6, 0, 16);
270}
271
272void inet_naddr_any(inet_naddr_t *naddr)
273{
274 naddr->version = ip_any;
275 memset(naddr->addr6, 0, 16);
276 naddr->prefix = 0;
277}
278
279int inet_addr_compare(const inet_addr_t *a, const inet_addr_t *b)
280{
281 if (a->version != b->version)
282 return 0;
283
284 switch (a->version) {
285 case ip_v4:
286 return (a->addr == b->addr);
287 case ip_v6:
288 return addr128_compare(a->addr6, b->addr6);
289 default:
290 return 0;
291 }
292}
293
294int inet_addr_is_any(const inet_addr_t *addr)
295{
296 return ((addr->version == ip_any) ||
297 (inet_addr_compare(addr, &inet_addr_any_addr)) ||
298 (inet_addr_compare(addr, &inet_addr_any_addr6)));
299}
300
301int inet_naddr_compare(const inet_naddr_t *naddr, const inet_addr_t *addr)
302{
303 if (naddr->version != addr->version)
304 return 0;
305
306 switch (naddr->version) {
307 case ip_v4:
308 return (naddr->addr == addr->addr);
309 case ip_v6:
310 return addr128_compare(naddr->addr6, addr->addr6);
311 default:
312 return 0;
313 }
314}
315
316int inet_naddr_compare_mask(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 if (naddr->prefix > 32)
324 return 0;
325
326 addr32_t mask =
327 BIT_RANGE(addr32_t, 31, 31 - (naddr->prefix - 1));
328 return ((naddr->addr & mask) == (addr->addr & mask));
329 case ip_v6:
330 if (naddr->prefix > 128)
331 return 0;
332
333 size_t pos = 0;
334 for (size_t i = 0; i < 16; i++) {
335 /* Further bits do not matter */
336 if (naddr->prefix < pos)
337 break;
338
339 if (naddr->prefix - pos > 8) {
340 /* Comparison without masking */
341 if (naddr->addr6[i] != addr->addr6[i])
342 return 0;
343 } else {
344 /* Comparison with masking */
345 uint8_t mask =
346 BIT_RANGE(uint8_t, 8, 8 - (naddr->prefix - pos - 1));
347 if ((naddr->addr6[i] & mask) != (addr->addr6[i] & mask))
348 return 0;
349 }
350
351 pos += 8;
352 }
353
354 return 1;
355 default:
356 return 0;
357 }
358}
359
360/** Parse node address.
361 *
362 * @param text Network address in common notation.
363 * @param addr Place to store node address.
364 *
365 * @return EOK on success, EINVAL if input is not in valid format.
366 *
367 */
368int inet_addr_parse(const char *text, inet_addr_t *addr)
369{
370 int rc = inet_addr_version(text, &addr->version);
371 if (rc != EOK)
372 return rc;
373
374 uint8_t buf[16];
375 rc = inet_pton(ipver_af(addr->version), text, buf);
376 if (rc != EOK)
377 return rc;
378
379 switch (addr->version) {
380 case ip_v4:
381 addr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
382 buf[3];
383 break;
384 case ip_v6:
385 memcpy(addr->addr6, buf, 16);
386 break;
387 default:
388 return EINVAL;
389 }
390
391 return EOK;
392}
393
394/** Parse network address.
395 *
396 * @param text Network address in common notation.
397 * @param naddr Place to store network address.
398 *
399 * @return EOK on success, EINVAL if input is not in valid format.
400 *
401 */
402int inet_naddr_parse(const char *text, inet_naddr_t *naddr)
403{
404 char *slash = str_chr(text, '/');
405 if (slash == NULL)
406 return EINVAL;
407
408 *slash = 0;
409
410 int rc = inet_addr_version(text, &naddr->version);
411 if (rc != EOK)
412 return rc;
413
414 uint8_t buf[16];
415 rc = inet_pton(ipver_af(naddr->version), text, buf);
416 *slash = '/';
417
418 if (rc != EOK)
419 return rc;
420
421 slash++;
422 uint8_t prefix;
423
424 switch (naddr->version) {
425 case ip_v4:
426 prefix = strtoul(slash, &slash, 10);
427 if (prefix > 32)
428 return EINVAL;
429
430 naddr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) |
431 buf[3];
432 naddr->prefix = prefix;
433
434 break;
435 case ip_v6:
436 prefix = strtoul(slash, &slash, 10);
437 if (prefix > 128)
438 return EINVAL;
439
440 memcpy(naddr->addr6, buf, 16);
441 naddr->prefix = prefix;
442
443 break;
444 default:
445 return ENOTSUP;
446 }
447
448 return EOK;
449}
450
451/** Format node address.
452 *
453 * @param addr Node address.
454 * @param bufp Place to store pointer to formatted string.
455 *
456 * @return EOK on success.
457 * @return ENOMEM if out of memory.
458 * @return ENOTSUP on unsupported address family.
459 *
460 */
461int inet_addr_format(const inet_addr_t *addr, char **bufp)
462{
463 int rc = 0;
464
465 switch (addr->version) {
466 case ip_any:
467 rc = asprintf(bufp, "none");
468 break;
469 case ip_v4:
470 rc = asprintf(bufp, "%u.%u.%u.%u", (addr->addr >> 24) & 0xff,
471 (addr->addr >> 16) & 0xff, (addr->addr >> 8) & 0xff,
472 addr->addr & 0xff);
473 break;
474 case ip_v6:
475 *bufp = (char *) malloc(INET6_ADDRSTRLEN);
476 if (*bufp == NULL)
477 return ENOMEM;
478
479 return inet_ntop(AF_INET6, addr->addr6, *bufp, INET6_ADDRSTRLEN);
480 default:
481 return ENOTSUP;
482 }
483
484 if (rc < 0)
485 return ENOMEM;
486
487 return EOK;
488}
489
490/** Format network address.
491 *
492 * @param naddr Network address.
493 * @param bufp Place to store pointer to formatted string.
494 *
495 * @return EOK on success.
496 * @return ENOMEM if out of memory.
497 * @return ENOTSUP on unsupported address family.
498 *
499 */
500int inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
501{
502 int rc = 0;
503 char prefix[INET_PREFIXSTRSIZE];
504
505 switch (naddr->version) {
506 case ip_any:
507 rc = asprintf(bufp, "none");
508 break;
509 case ip_v4:
510 rc = asprintf(bufp, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8
511 "/%" PRIu8, (naddr->addr >> 24) & 0xff,
512 (naddr->addr >> 16) & 0xff, (naddr->addr >> 8) & 0xff,
513 naddr->addr & 0xff, naddr->prefix);
514 break;
515 case ip_v6:
516 *bufp = (char *) malloc(INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
517 if (*bufp == NULL)
518 return ENOMEM;
519
520 rc = inet_ntop(AF_INET6, naddr->addr6, *bufp,
521 INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE);
522 if (rc != EOK) {
523 free(*bufp);
524 return rc;
525 }
526
527 rc = snprintf(prefix, INET_PREFIXSTRSIZE, "/%" PRIu8,
528 naddr->prefix);
529 if (rc < 0) {
530 free(*bufp);
531 return ENOMEM;
532 }
533
534 str_append(*bufp, INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE, prefix);
535
536 break;
537 default:
538 return ENOTSUP;
539 }
540
541 if (rc < 0)
542 return ENOMEM;
543
544 return EOK;
545}
546
547ip_ver_t inet_addr_get(const inet_addr_t *addr, addr32_t *v4, addr128_t *v6)
548{
549 switch (addr->version) {
550 case ip_v4:
551 if (v4 != NULL)
552 *v4 = addr->addr;
553 break;
554 case ip_v6:
555 if (v6 != NULL)
556 memcpy(*v6, addr->addr6, 16);
557 break;
558 default:
559 assert(false);
560 break;
561 }
562
563 return addr->version;
564}
565
566ip_ver_t inet_naddr_get(const inet_naddr_t *naddr, addr32_t *v4, addr128_t *v6,
567 uint8_t *prefix)
568{
569 switch (naddr->version) {
570 case ip_v4:
571 if (v4 != NULL)
572 *v4 = naddr->addr;
573 if (prefix != NULL)
574 *prefix = naddr->prefix;
575 break;
576 case ip_v6:
577 if (v6 != NULL)
578 memcpy(*v6, naddr->addr6, 16);
579 if (prefix != NULL)
580 *prefix = naddr->prefix;
581 break;
582 default:
583 assert(false);
584 break;
585 }
586
587 return naddr->version;
588}
589
590void inet_addr_set(addr32_t v4, inet_addr_t *addr)
591{
592 addr->version = ip_v4;
593 addr->addr = v4;
594}
595
596void inet_naddr_set(addr32_t v4, uint8_t prefix, inet_naddr_t *naddr)
597{
598 naddr->version = ip_v4;
599 naddr->addr = v4;
600 naddr->prefix = prefix;
601}
602
603void inet_sockaddr_in_addr(const sockaddr_in_t *sockaddr_in, inet_addr_t *addr)
604{
605 addr->version = ip_v4;
606 addr->addr = uint32_t_be2host(sockaddr_in->sin_addr.s_addr);
607}
608
609void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
610{
611 addr->version = ip_v6;
612 memcpy(addr->addr6, v6, 16);
613}
614
615void inet_naddr_set6(addr128_t v6, uint8_t prefix, inet_naddr_t *naddr)
616{
617 naddr->version = ip_v6;
618 memcpy(naddr->addr6, v6, 16);
619 naddr->prefix = prefix;
620}
621
622void inet_sockaddr_in6_addr(const sockaddr_in6_t *sockaddr_in6,
623 inet_addr_t *addr)
624{
625 addr->version = ip_v6;
626 addr128_t_be2host(sockaddr_in6->sin6_addr.s6_addr, addr->addr6);
627}
628
629uint16_t inet_addr_sockaddr_in(const inet_addr_t *addr,
630 sockaddr_in_t *sockaddr_in, sockaddr_in6_t *sockaddr_in6)
631{
632 switch (addr->version) {
633 case ip_v4:
634 if (sockaddr_in != NULL) {
635 sockaddr_in->sin_family = AF_INET;
636 sockaddr_in->sin_addr.s_addr = host2uint32_t_be(addr->addr);
637 }
638 break;
639 case ip_v6:
640 if (sockaddr_in6 != NULL) {
641 sockaddr_in6->sin6_family = AF_INET6;
642 host2addr128_t_be(addr->addr6, sockaddr_in6->sin6_addr.s6_addr);
643 }
644 break;
645 default:
646 assert(false);
647 break;
648 }
649
650 return ipver_af(addr->version);
651}
652
653/** @}
654 */
Note: See TracBrowser for help on using the repository browser.