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

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

add basic infrastructure for IPv6 (inactive)
make inet_addr_t a universal address type

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