Changes in uspace/lib/c/generic/inet/addr.c [683e584:26de91a] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/inet/addr.c
r683e584 r26de91a 1 1 /* 2 2 * Copyright (c) 2013 Jiri Svoboda 3 * Copyright (c) 2013 Martin Decky4 3 * All rights reserved. 5 4 * … … 37 36 #include <errno.h> 38 37 #include <unistd.h> 38 #include <net/socket_codes.h> 39 39 #include <inet/addr.h> 40 #include <net/inet.h> 40 41 #include <stdio.h> 41 42 #include <malloc.h> … … 43 44 44 45 #define INET_PREFIXSTRSIZE 5 45 46 #define INET6_ADDRSTRLEN (8 * 4 + 7 + 1)47 46 48 47 #if !(defined(__BE__) ^ defined(__LE__)) … … 181 180 } 182 181 182 /** Determine address version. 183 * 184 * @param text Address in common notation. 185 * @param af Place to store address version. 186 * 187 * @return EOK on success, EINVAL if input is not in valid format. 188 * 189 */ 190 static int inet_addr_version(const char *text, ip_ver_t *ver) 191 { 192 char *dot = str_chr(text, '.'); 193 if (dot != NULL) { 194 *ver = ip_v4; 195 return EOK; 196 } 197 198 char *collon = str_chr(text, ':'); 199 if (collon != NULL) { 200 *ver = ip_v6; 201 return EOK; 202 } 203 204 return EINVAL; 205 } 206 207 static int ipver_af(ip_ver_t ver) 208 { 209 switch (ver) { 210 case ip_any: 211 return AF_NONE; 212 case ip_v4: 213 return AF_INET; 214 case ip_v6: 215 return AF_INET6; 216 default: 217 assert(false); 218 return EINVAL; 219 } 220 } 221 222 ip_ver_t ipver_from_af(int af) 223 { 224 switch (af) { 225 case AF_NONE: 226 return ip_any; 227 case AF_INET: 228 return ip_v4; 229 case AF_INET6: 230 return ip_v6; 231 default: 232 assert(false); 233 return EINVAL; 234 } 235 } 236 183 237 void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr) 184 238 { … … 234 288 if (naddr->version != addr->version) 235 289 return 0; 236 290 237 291 switch (naddr->version) { 238 292 case ip_v4: … … 261 315 if (naddr->prefix > 128) 262 316 return 0; 263 317 264 318 size_t pos = 0; 265 319 for (size_t i = 0; i < 16; i++) { … … 267 321 if (naddr->prefix < pos) 268 322 break; 269 323 270 324 if (naddr->prefix - pos > 8) { 271 325 /* Comparison without masking */ … … 279 333 return 0; 280 334 } 281 335 282 336 pos += 8; 283 337 } 284 338 285 339 return 1; 286 340 default: 287 341 return 0; 288 342 } 289 }290 291 static int inet_addr_parse_v4(const char *str, inet_addr_t *raddr,292 int *prefix)293 {294 uint32_t a = 0;295 uint8_t b;296 char *cur = (char *)str;297 size_t i = 0;298 299 while (i < 4) {300 int rc = str_uint8_t(cur, (const char **)&cur, 10, false, &b);301 if (rc != EOK)302 return rc;303 304 a = (a << 8) + b;305 306 i++;307 308 if (*cur == '\0')309 break;310 311 if (*cur != '.')312 return EINVAL;313 314 if (i < 4)315 cur++;316 }317 318 if (prefix != NULL) {319 *prefix = strtoul(cur, &cur, 10);320 if (*prefix > 32)321 return EINVAL;322 }323 324 if (i != 4 || (*cur != '\0'))325 return EINVAL;326 327 raddr->version = ip_v4;328 raddr->addr = a;329 330 return EOK;331 }332 333 static int inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix)334 {335 uint8_t data[16];336 337 memset(data, 0, 16);338 339 const char *cur = str;340 size_t i = 0;341 size_t wildcard_pos = (size_t) -1;342 size_t wildcard_size = 0;343 344 /* Handle initial wildcard */345 if ((str[0] == ':') && (str[1] == ':')) {346 cur = str + 2;347 wildcard_pos = 0;348 wildcard_size = 16;349 350 /* Handle the unspecified address */351 if (*cur == '\0')352 goto success;353 }354 355 while (i < 16) {356 uint16_t bioctet;357 int rc = str_uint16_t(cur, &cur, 16, false, &bioctet);358 if (rc != EOK)359 return rc;360 361 data[i] = (bioctet >> 8) & 0xff;362 data[i + 1] = bioctet & 0xff;363 364 if (wildcard_pos != (size_t) -1) {365 if (wildcard_size < 2)366 return EINVAL;367 368 wildcard_size -= 2;369 }370 371 i += 2;372 373 if (*cur != ':')374 break;375 376 if (i < 16) {377 cur++;378 379 /* Handle wildcard */380 if (*cur == ':') {381 if (wildcard_pos != (size_t) -1)382 return EINVAL;383 384 wildcard_pos = i;385 wildcard_size = 16 - i;386 cur++;387 388 if (*cur == '\0' || *cur == '/')389 break;390 }391 }392 }393 394 if (prefix != NULL) {395 if (*cur != '/')396 return EINVAL;397 cur++;398 399 *prefix = strtoul(cur, (char **)&cur, 10);400 if (*prefix > 128)401 return EINVAL;402 }403 404 if (*cur != '\0')405 return EINVAL;406 407 /* Create wildcard positions */408 if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) {409 size_t wildcard_shift = 16 - wildcard_size;410 411 for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) {412 size_t j = i - 1;413 data[j + wildcard_size] = data[j];414 data[j] = 0;415 }416 }417 418 success:419 raddr->version = ip_v6;420 memcpy(raddr->addr6, data, 16);421 return EOK;422 343 } 423 344 … … 432 353 int inet_addr_parse(const char *text, inet_addr_t *addr) 433 354 { 434 int rc; 435 436 rc = inet_addr_parse_v4(text, addr, NULL); 437 if (rc == EOK) 438 return EOK; 439 440 rc = inet_addr_parse_v6(text, addr, NULL); 441 if (rc == EOK) 442 return EOK; 443 444 return EINVAL; 355 int rc = inet_addr_version(text, &addr->version); 356 if (rc != EOK) 357 return rc; 358 359 uint8_t buf[16]; 360 rc = inet_pton(ipver_af(addr->version), text, buf); 361 if (rc != EOK) 362 return rc; 363 364 switch (addr->version) { 365 case ip_v4: 366 addr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | 367 buf[3]; 368 break; 369 case ip_v6: 370 memcpy(addr->addr6, buf, 16); 371 break; 372 default: 373 return EINVAL; 374 } 375 376 return EOK; 445 377 } 446 378 … … 455 387 int inet_naddr_parse(const char *text, inet_naddr_t *naddr) 456 388 { 457 int rc; 458 inet_addr_t addr; 459 int prefix; 460 461 rc = inet_addr_parse_v4(text, &addr, &prefix); 462 if (rc == EOK) { 463 inet_addr_naddr(&addr, prefix, naddr); 464 return EOK; 465 } 466 467 rc = inet_addr_parse_v6(text, &addr, &prefix); 468 if (rc == EOK) { 469 inet_addr_naddr(&addr, prefix, naddr); 470 return EOK; 471 } 472 473 return EINVAL; 474 } 475 476 static int inet_addr_format_v4(addr32_t addr, char **bufp) 477 { 478 int rc; 479 480 rc = asprintf(bufp, "%u.%u.%u.%u", (addr >> 24) & 0xff, 481 (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); 482 if (rc < 0) 483 return ENOMEM; 484 485 return EOK; 486 } 487 488 static int inet_addr_format_v6(const addr128_t addr, char **bufp) 489 { 490 *bufp = (char *) malloc(INET6_ADDRSTRLEN); 491 if (*bufp == NULL) 492 return ENOMEM; 493 494 /* Find the longest zero subsequence */ 495 496 uint16_t zeroes[8]; 497 uint16_t bioctets[8]; 498 499 for (size_t i = 8; i > 0; i--) { 500 size_t j = i - 1; 501 502 bioctets[j] = (addr[j << 1] << 8) | addr[(j << 1) + 1]; 503 504 if (bioctets[j] == 0) { 505 zeroes[j] = 1; 506 if (j < 7) 507 zeroes[j] += zeroes[j + 1]; 508 } else 509 zeroes[j] = 0; 510 } 511 512 size_t wildcard_pos = (size_t) -1; 513 size_t wildcard_size = 0; 514 515 for (size_t i = 0; i < 8; i++) { 516 if (zeroes[i] > wildcard_size) { 517 wildcard_pos = i; 518 wildcard_size = zeroes[i]; 519 } 520 } 521 522 char *cur = *bufp; 523 size_t rest = INET6_ADDRSTRLEN; 524 bool tail_zero = false; 525 int ret; 526 527 for (size_t i = 0; i < 8; i++) { 528 if ((i == wildcard_pos) && (wildcard_size > 1)) { 529 ret = snprintf(cur, rest, ":"); 530 i += wildcard_size - 1; 531 tail_zero = true; 532 } else if (i == 0) { 533 ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]); 534 tail_zero = false; 535 } else { 536 ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]); 537 tail_zero = false; 538 } 539 540 if (ret < 0) 389 char *slash = str_chr(text, '/'); 390 if (slash == NULL) 391 return EINVAL; 392 393 *slash = 0; 394 395 int rc = inet_addr_version(text, &naddr->version); 396 if (rc != EOK) 397 return rc; 398 399 uint8_t buf[16]; 400 rc = inet_pton(ipver_af(naddr->version), text, buf); 401 *slash = '/'; 402 403 if (rc != EOK) 404 return rc; 405 406 slash++; 407 uint8_t prefix; 408 409 switch (naddr->version) { 410 case ip_v4: 411 prefix = strtoul(slash, &slash, 10); 412 if (prefix > 32) 541 413 return EINVAL; 542 543 cur += ret; 544 rest -= ret; 545 } 546 547 if (tail_zero) 548 (void) snprintf(cur, rest, ":"); 549 414 415 naddr->addr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | 416 buf[3]; 417 naddr->prefix = prefix; 418 419 break; 420 case ip_v6: 421 prefix = strtoul(slash, &slash, 10); 422 if (prefix > 128) 423 return EINVAL; 424 425 memcpy(naddr->addr6, buf, 16); 426 naddr->prefix = prefix; 427 428 break; 429 default: 430 return ENOTSUP; 431 } 432 550 433 return EOK; 551 434 } … … 563 446 int inet_addr_format(const inet_addr_t *addr, char **bufp) 564 447 { 565 int rc; 566 567 rc = ENOTSUP; 568 448 int rc = 0; 449 569 450 switch (addr->version) { 570 451 case ip_any: 571 452 rc = asprintf(bufp, "none"); 572 if (rc < 0) 453 break; 454 case ip_v4: 455 rc = asprintf(bufp, "%u.%u.%u.%u", (addr->addr >> 24) & 0xff, 456 (addr->addr >> 16) & 0xff, (addr->addr >> 8) & 0xff, 457 addr->addr & 0xff); 458 break; 459 case ip_v6: 460 *bufp = (char *) malloc(INET6_ADDRSTRLEN); 461 if (*bufp == NULL) 573 462 return ENOMEM; 574 rc = EOK; 575 break; 576 case ip_v4: 577 rc = inet_addr_format_v4(addr->addr, bufp); 578 break; 579 case ip_v6: 580 rc = inet_addr_format_v6(addr->addr6, bufp); 581 break; 582 } 583 584 return rc; 463 464 return inet_ntop(AF_INET6, addr->addr6, *bufp, INET6_ADDRSTRLEN); 465 default: 466 return ENOTSUP; 467 } 468 469 if (rc < 0) 470 return ENOMEM; 471 472 return EOK; 585 473 } 586 474 … … 597 485 int inet_naddr_format(const inet_naddr_t *naddr, char **bufp) 598 486 { 599 int rc; 600 char *astr; 601 602 rc = ENOTSUP; 603 487 int rc = 0; 488 char prefix[INET_PREFIXSTRSIZE]; 489 604 490 switch (naddr->version) { 605 491 case ip_any: 606 492 rc = asprintf(bufp, "none"); 607 if (rc < 0) 493 break; 494 case ip_v4: 495 rc = asprintf(bufp, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 496 "/%" PRIu8, (naddr->addr >> 24) & 0xff, 497 (naddr->addr >> 16) & 0xff, (naddr->addr >> 8) & 0xff, 498 naddr->addr & 0xff, naddr->prefix); 499 break; 500 case ip_v6: 501 *bufp = (char *) malloc(INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE); 502 if (*bufp == NULL) 608 503 return ENOMEM; 609 rc = EOK; 610 break; 611 case ip_v4: 612 rc = inet_addr_format_v4(naddr->addr, &astr); 613 if (rc != EOK) 614 return ENOMEM; 615 616 rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix); 504 505 rc = inet_ntop(AF_INET6, naddr->addr6, *bufp, 506 INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE); 507 if (rc != EOK) { 508 free(*bufp); 509 return rc; 510 } 511 512 rc = snprintf(prefix, INET_PREFIXSTRSIZE, "/%" PRIu8, 513 naddr->prefix); 617 514 if (rc < 0) { 618 free( astr);515 free(*bufp); 619 516 return ENOMEM; 620 517 } 621 622 rc = EOK; 623 break; 624 case ip_v6: 625 rc = inet_addr_format_v6(naddr->addr6, &astr); 626 if (rc != EOK) 627 return ENOMEM; 628 629 rc = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix); 630 if (rc < 0) { 631 free(astr); 632 return ENOMEM; 633 } 634 635 rc = EOK; 636 break; 637 } 638 639 return rc; 518 519 str_append(*bufp, INET6_ADDRSTRLEN + INET_PREFIXSTRSIZE, prefix); 520 521 break; 522 default: 523 return ENOTSUP; 524 } 525 526 if (rc < 0) 527 return ENOMEM; 528 529 return EOK; 640 530 } 641 531 … … 696 586 } 697 587 588 void inet_sockaddr_in_addr(const sockaddr_in_t *sockaddr_in, inet_addr_t *addr) 589 { 590 addr->version = ip_v4; 591 addr->addr = uint32_t_be2host(sockaddr_in->sin_addr.s_addr); 592 } 593 698 594 void inet_addr_set6(addr128_t v6, inet_addr_t *addr) 699 595 { … … 709 605 } 710 606 607 void inet_sockaddr_in6_addr(const sockaddr_in6_t *sockaddr_in6, 608 inet_addr_t *addr) 609 { 610 addr->version = ip_v6; 611 addr128_t_be2host(sockaddr_in6->sin6_addr.s6_addr, addr->addr6); 612 } 613 614 uint16_t inet_addr_sockaddr_in(const inet_addr_t *addr, 615 sockaddr_in_t *sockaddr_in, sockaddr_in6_t *sockaddr_in6) 616 { 617 switch (addr->version) { 618 case ip_v4: 619 if (sockaddr_in != NULL) { 620 sockaddr_in->sin_family = AF_INET; 621 sockaddr_in->sin_addr.s_addr = host2uint32_t_be(addr->addr); 622 } 623 break; 624 case ip_v6: 625 if (sockaddr_in6 != NULL) { 626 sockaddr_in6->sin6_family = AF_INET6; 627 host2addr128_t_be(addr->addr6, sockaddr_in6->sin6_addr.s6_addr); 628 } 629 break; 630 default: 631 assert(false); 632 break; 633 } 634 635 return ipver_af(addr->version); 636 } 637 638 int inet_addr_sockaddr(const inet_addr_t *addr, uint16_t port, 639 sockaddr_t **nsockaddr, socklen_t *naddrlen) 640 { 641 sockaddr_in_t *sa4; 642 sockaddr_in6_t *sa6; 643 644 switch (addr->version) { 645 case ip_v4: 646 sa4 = calloc(1, sizeof(sockaddr_in_t)); 647 if (sa4 == NULL) 648 return ENOMEM; 649 650 sa4->sin_family = AF_INET; 651 sa4->sin_port = host2uint16_t_be(port); 652 sa4->sin_addr.s_addr = host2uint32_t_be(addr->addr); 653 if (nsockaddr != NULL) 654 *nsockaddr = (sockaddr_t *)sa4; 655 if (naddrlen != NULL) 656 *naddrlen = sizeof(*sa4); 657 break; 658 case ip_v6: 659 sa6 = calloc(1, sizeof(sockaddr_in6_t)); 660 if (sa6 == NULL) 661 return ENOMEM; 662 663 sa6->sin6_family = AF_INET6; 664 sa6->sin6_port = host2uint16_t_be(port); 665 host2addr128_t_be(addr->addr6, sa6->sin6_addr.s6_addr); 666 if (nsockaddr != NULL) 667 *nsockaddr = (sockaddr_t *)sa6; 668 if (naddrlen != NULL) 669 *naddrlen = sizeof(*sa6); 670 break; 671 default: 672 assert(false); 673 break; 674 } 675 676 return EOK; 677 } 678 711 679 /** @} 712 680 */
Note:
See TracChangeset
for help on using the changeset viewer.