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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a17356fd was 671b546, checked in by Martin Decky <martin@…>, 12 years ago

addr128_t comparison operator

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