1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 10 #if (NXT_INET6) 11 static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end); 12 #endif 13 14 static nxt_int_t nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs); 15 static nxt_int_t nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs); 16 static nxt_int_t nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs); 17 18 19 nxt_sockaddr_t * 20 nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length) 21 { 22 size_t size; 23 nxt_sockaddr_t *sa; 24 25 size = offsetof(nxt_sockaddr_t, u) + socklen + address_length; 26 27 /* 28 * The current struct sockaddr's define 32-bit fields at maximum 29 * and may define 64-bit AF_INET6 fields in the future. Alignment 30 * of memory allocated by nxt_mp_zalloc() is enough for these fields. 31 * If 128-bit alignment will be required then nxt_mem_malloc() and 32 * nxt_memzero() should be used instead. 33 */ 34 35 sa = nxt_mp_zalloc(mp, size); 36 37 if (nxt_fast_path(sa != NULL)) { 38 sa->socklen = socklen; 39 sa->length = address_length; 40 sa->sockaddr_size = size; 41 } 42 43 return sa; 44 } 45 46 47 nxt_sockaddr_t * 48 nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length, 49 size_t address_length) 50 { 51 size_t size, copy; 52 nxt_sockaddr_t *sa; 53 54 size = length; 55 copy = length; 56 57 #if (NXT_HAVE_UNIX_DOMAIN) 58 59 /* 60 * Unspecified Unix domain sockaddr_un form and length are very 61 * platform depended (see comment in unix/socket.h). Here they are 62 * normalized to the sockaddr_un with single zero byte sun_path[]. 63 */ 64 65 if (size <= offsetof(struct sockaddr_un, sun_path)) { 66 /* 67 * Small socket length means a short unspecified Unix domain 68 * socket address: 69 * 70 * getsockname() and getpeername() on OpenBSD prior to 5.3 71 * return zero length and does not update a passed sockaddr 72 * buffer at all. 73 * 74 * Linux returns length equal to 2, i.e. sockaddr_un without 75 * sun_path[], unix(7): 76 * 77 * unnamed: A stream socket that has not been bound 78 * to a pathname using bind(2) has no name. Likewise, 79 * the two sockets created by socketpair(2) are unnamed. 80 * When the address of an unnamed socket is returned by 81 * getsockname(2), getpeername(2), and accept(2), its 82 * length is sizeof(sa_family_t), and sun_path should 83 * not be inspected. 84 */ 85 size = offsetof(struct sockaddr_un, sun_path) + 1; 86 87 #if !(NXT_LINUX) 88 89 } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') { 90 /* 91 * Omit nonsignificant zeros of the unspecified Unix domain socket 92 * address. This test is disabled for Linux since Linux abstract 93 * socket address also starts with zero. However Linux unspecified 94 * Unix domain socket address is short and is handled above. 95 */ 96 size = offsetof(struct sockaddr_un, sun_path) + 1; 97 copy = size; 98 99 #endif 100 } 101 102 #endif /* NXT_HAVE_UNIX_DOMAIN */ 103 104 sa = nxt_sockaddr_alloc(mp, size, address_length); 105 106 if (nxt_fast_path(sa != NULL)) { 107 nxt_memcpy(&sa->u.sockaddr, sockaddr, copy); 108 109 #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD) 110 111 if (length == 0) { 112 sa->u.sockaddr.sa_family = AF_UNIX; 113 } 114 115 #endif 116 } 117 118 return sa; 119 } 120 121 122 nxt_sockaddr_t * 123 nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src) 124 { 125 size_t length; 126 nxt_sockaddr_t *dst; 127 128 length = offsetof(nxt_sockaddr_t, u) + src->socklen; 129 130 dst = nxt_mp_alloc(mp, length); 131 132 if (nxt_fast_path(dst != NULL)) { 133 nxt_memcpy(dst, src, length); 134 } 135 136 return dst; 137 } 138 139 140 nxt_sockaddr_t * 141 nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s) 142 { 143 int ret; 144 size_t length; 145 socklen_t socklen; 146 nxt_sockaddr_buf_t sockaddr; 147 148 socklen = NXT_SOCKADDR_LEN; 149 150 ret = getsockname(s, &sockaddr.buf, &socklen); 151 152 if (nxt_fast_path(ret == 0)) { 153 154 switch (sockaddr.buf.sa_family) { 155 #if (NXT_INET6) 156 case AF_INET6: 157 length = NXT_INET6_ADDR_STR_LEN; 158 break; 159 #endif 160 161 #if (NXT_HAVE_UNIX_DOMAIN) 162 case AF_UNIX: 163 length = sizeof("unix:") - 1 + socklen; 164 #endif 165 break; 166 167 case AF_INET: 168 length = NXT_INET_ADDR_STR_LEN; 169 break; 170 171 default: 172 length = 0; 173 break; 174 } 175 176 return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length); 177 } 178 179 nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno); 180 181 return NULL; 182 } 183 184 185 void 186 nxt_sockaddr_text(nxt_sockaddr_t *sa) 187 { 188 size_t offset; 189 u_char *p, *start, *end, *octet; 190 uint32_t port; 191 192 end = nxt_pointer_to(sa, sa->sockaddr_size); 193 194 switch (sa->u.sockaddr.sa_family) { 195 196 case AF_INET: 197 offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in); 198 199 sa->start = offset; 200 sa->address_start = offset; 201 202 start = nxt_pointer_to(sa, offset); 203 octet = (u_char *) &sa->u.sockaddr_in.sin_addr; 204 205 p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud", 206 octet[0], octet[1], octet[2], octet[3]); 207 208 sa->address_length = p - start; 209 sa->port_start = sa->address_length + 1; 210 211 port = sa->u.sockaddr_in.sin_port; 212 213 break; 214 215 #if (NXT_INET6) 216 217 case AF_INET6: 218 offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_in6); 219 220 sa->start = offset; 221 sa->address_start = offset; 222 223 start = nxt_pointer_to(sa, offset); 224 p = start; 225 226 *p++ = '['; 227 228 p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 229 230 sa->address_length = p - (start + 1); 231 sa->port_start = sa->address_length + 2; 232 233 *p++ = ']'; 234 235 port = sa->u.sockaddr_in6.sin6_port; 236 237 break; 238 239 #endif 240 241 #if (NXT_HAVE_UNIX_DOMAIN) 242 243 case AF_UNIX: 244 245 offset = offsetof(nxt_sockaddr_t, u) + sizeof(struct sockaddr_un); 246 247 sa->start = offset; 248 sa->address_start = offset; 249 250 start = nxt_pointer_to(sa, offset); 251 p = start; 252 253 #if (NXT_LINUX) 254 255 p = (u_char *) sa->u.sockaddr_un.sun_path; 256 257 if (p[0] == '\0') { 258 int length; 259 260 /* Linux abstract socket address has no trailing zero. */ 261 length = sa->socklen - offsetof(struct sockaddr_un, sun_path); 262 263 p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1); 264 265 } else { 266 p = nxt_sprintf(start, end, "unix:%s", p); 267 } 268 269 #else /* !(NXT_LINUX) */ 270 271 p = nxt_sprintf(start, end, "unix:%s", p); 272 273 #endif 274 275 sa->address_length = p - start; 276 sa->port_start = sa->address_length; 277 sa->length = p - start; 278 279 return; 280 281 #endif /* NXT_HAVE_UNIX_DOMAIN */ 282 283 default: 284 return; 285 } 286 287 p = nxt_sprintf(p, end, ":%d", ntohs(port)); 288 289 sa->length = p - start; 290 } 291 292 293 uint32_t 294 nxt_sockaddr_port_number(nxt_sockaddr_t *sa) 295 { 296 uint32_t port; 297 298 switch (sa->u.sockaddr.sa_family) { 299 300 #if (NXT_INET6) 301 302 case AF_INET6: 303 port = sa->u.sockaddr_in6.sin6_port; 304 break; 305 306 #endif 307 308 #if (NXT_HAVE_UNIX_DOMAIN) 309 310 case AF_UNIX: 311 return 0; 312 313 #endif 314 315 default: 316 port = sa->u.sockaddr_in.sin_port; 317 break; 318 } 319 320 return ntohs((uint16_t) port); 321 } 322 323 324 nxt_bool_t 325 nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2) 326 { 327 if (sa1->socklen != sa2->socklen) { 328 return 0; 329 } 330 331 if (sa1->type != sa2->type) { 332 return 0; 333 } 334 335 if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) { 336 return 0; 337 } 338 339 /* 340 * sockaddr struct's cannot be compared in whole since kernel 341 * may fill some fields in inherited sockaddr struct's. 342 */ 343 344 switch (sa1->u.sockaddr.sa_family) { 345 346 #if (NXT_INET6) 347 348 case AF_INET6: 349 if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) { 350 return 0; 351 } 352 353 if (nxt_memcmp(&sa1->u.sockaddr_in6.sin6_addr, 354 &sa2->u.sockaddr_in6.sin6_addr, 16) 355 != 0) 356 { 357 return 0; 358 } 359 360 return 1; 361 362 #endif 363 364 #if (NXT_HAVE_UNIX_DOMAIN) 365 366 case AF_UNIX: 367 { 368 size_t length; 369 370 length = sa1->socklen - offsetof(struct sockaddr_un, sun_path); 371 372 if (nxt_memcmp(&sa1->u.sockaddr_un.sun_path, 373 &sa2->u.sockaddr_un.sun_path, length) 374 != 0) 375 { 376 return 0; 377 } 378 379 return 1; 380 } 381 382 #endif 383 384 default: /* AF_INET */ 385 if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) { 386 return 0; 387 } 388 389 if (sa1->u.sockaddr_in.sin_addr.s_addr 390 != sa2->u.sockaddr_in.sin_addr.s_addr) 391 { 392 return 0; 393 } 394 395 return 1; 396 } 397 } 398 399 400 size_t 401 nxt_sockaddr_ntop(nxt_sockaddr_t *sa, u_char *buf, u_char *end, nxt_bool_t port) 402 { 403 u_char *p; 404 405 switch (sa->u.sockaddr.sa_family) { 406 407 case AF_INET: 408 p = (u_char *) &sa->u.sockaddr_in.sin_addr; 409 410 if (port) { 411 p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud:%d", 412 p[0], p[1], p[2], p[3], 413 ntohs(sa->u.sockaddr_in.sin_port)); 414 } else { 415 p = nxt_sprintf(buf, end, "%ud.%ud.%ud.%ud", 416 p[0], p[1], p[2], p[3]); 417 } 418 419 return p - buf; 420 421 #if (NXT_INET6) 422 423 case AF_INET6: 424 p = buf; 425 426 if (port) { 427 *p++ = '['; 428 } 429 430 p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end); 431 432 if (port) { 433 p = nxt_sprintf(p, end, "]:%d", 434 ntohs(sa->u.sockaddr_in6.sin6_port)); 435 } 436 437 return p - buf; 438 #endif 439 440 #if (NXT_HAVE_UNIX_DOMAIN) 441 442 case AF_UNIX: 443 444 #if (NXT_LINUX) 445 446 p = (u_char *) sa->u.sockaddr_un.sun_path; 447 448 if (p[0] == '\0') { 449 int length; 450 451 /* Linux abstract socket address has no trailing zero. */ 452 453 length = sa->socklen - offsetof(struct sockaddr_un, sun_path) - 1; 454 p = nxt_sprintf(buf, end, "unix:\\0%*s", length, p + 1); 455 456 } else { 457 p = nxt_sprintf(buf, end, "unix:%s", p); 458 } 459 460 #else /* !(NXT_LINUX) */ 461 462 p = nxt_sprintf(buf, end, "unix:%s", sa->u.sockaddr_un.sun_path); 463 464 #endif 465 466 return p - buf; 467 468 #endif /* NXT_HAVE_UNIX_DOMAIN */ 469 470 default: 471 return 0; 472 } 473 } 474 475 476 #if (NXT_INET6) 477 478 static u_char * 479 nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end) 480 { 481 u_char *p; 482 size_t zero_groups, last_zero_groups, ipv6_bytes; 483 nxt_uint_t i, zero_start, last_zero_start; 484 485 if (buf + NXT_INET6_ADDR_STR_LEN > end) { 486 return buf; 487 } 488 489 zero_start = 8; 490 zero_groups = 0; 491 last_zero_start = 8; 492 last_zero_groups = 0; 493 494 for (i = 0; i < 16; i += 2) { 495 496 if (addr[i] == 0 && addr[i + 1] == 0) { 497 498 if (last_zero_groups == 0) { 499 last_zero_start = i; 500 } 501 502 last_zero_groups++; 503 504 } else { 505 if (zero_groups < last_zero_groups) { 506 zero_groups = last_zero_groups; 507 zero_start = last_zero_start; 508 } 509 510 last_zero_groups = 0; 511 } 512 } 513 514 if (zero_groups < last_zero_groups) { 515 zero_groups = last_zero_groups; 516 zero_start = last_zero_start; 517 } 518 519 ipv6_bytes = 16; 520 p = buf; 521 522 if (zero_start == 0) { 523 524 /* IPv4-mapped address */ 525 if ((zero_groups == 5 && addr[10] == 0xff && addr[11] == 0xff) 526 /* IPv4-compatible address */ 527 || (zero_groups == 6) 528 /* not IPv6 loopback address */ 529 || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1)) 530 { 531 ipv6_bytes = 12; 532 } 533 534 *p++ = ':'; 535 } 536 537 for (i = 0; i < ipv6_bytes; i += 2) { 538 539 if (i == zero_start) { 540 /* Output maximum number of consecutive zero groups as "::". */ 541 i += (zero_groups - 1) * 2; 542 *p++ = ':'; 543 continue; 544 } 545 546 p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]); 547 548 if (i < 14) { 549 *p++ = ':'; 550 } 551 } 552 553 if (ipv6_bytes == 12) { 554 p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud", 555 addr[12], addr[13], addr[14], addr[15]); 556 } 557 558 return p; 559 } 560 561 #endif 562 563 564 void 565 nxt_job_sockaddr_parse(nxt_job_sockaddr_parse_t *jbs) 566 { 567 u_char *p; 568 size_t length; 569 nxt_int_t ret; 570 nxt_work_handler_t handler; 571 572 nxt_job_set_name(&jbs->resolve.job, "job sockaddr parse"); 573 574 length = jbs->addr.length; 575 p = jbs->addr.start; 576 577 if (length > 6 && nxt_memcmp(p, "unix:", 5) == 0) { 578 ret = nxt_job_sockaddr_unix_parse(jbs); 579 580 } else if (length != 0 && *p == '[') { 581 ret = nxt_job_sockaddr_inet6_parse(jbs); 582 583 } else { 584 ret = nxt_job_sockaddr_inet_parse(jbs); 585 } 586 587 switch (ret) { 588 589 case NXT_OK: 590 handler = jbs->resolve.ready_handler; 591 break; 592 593 case NXT_ERROR: 594 handler = jbs->resolve.error_handler; 595 break; 596 597 default: /* NXT_AGAIN */ 598 return; 599 } 600 601 nxt_job_return(jbs->resolve.job.task, &jbs->resolve.job, handler); 602 } 603 604 605 static nxt_int_t 606 nxt_job_sockaddr_unix_parse(nxt_job_sockaddr_parse_t *jbs) 607 { 608 #if (NXT_HAVE_UNIX_DOMAIN) 609 size_t length, socklen; 610 u_char *path; 611 nxt_mp_t *mp; 612 nxt_sockaddr_t *sa; 613 614 /* 615 * Actual sockaddr_un length can be lesser or even larger than defined 616 * struct sockaddr_un length (see comment in unix/nxt_socket.h). So 617 * limit maximum Unix domain socket address length by defined sun_path[] 618 * length because some OSes accept addresses twice larger than defined 619 * struct sockaddr_un. Also reserve space for a trailing zero to avoid 620 * ambiguity, since many OSes accept Unix domain socket addresses 621 * without a trailing zero. 622 */ 623 const size_t max_len = sizeof(struct sockaddr_un) 624 - offsetof(struct sockaddr_un, sun_path) - 1; 625 626 /* cutting "unix:" */ 627 length = jbs->addr.length - 5; 628 path = jbs->addr.start + 5; 629 630 if (length > max_len) { 631 nxt_thread_log_error(jbs->resolve.log_level, 632 "unix domain socket \"%V\" name is too long", 633 &jbs->addr); 634 return NXT_ERROR; 635 } 636 637 socklen = offsetof(struct sockaddr_un, sun_path) + length + 1; 638 639 #if (NXT_LINUX) 640 641 /* 642 * Linux unix(7): 643 * 644 * abstract: an abstract socket address is distinguished by the fact 645 * that sun_path[0] is a null byte ('\0'). The socket's address in 646 * this namespace is given by the additional bytes in sun_path that 647 * are covered by the specified length of the address structure. 648 * (Null bytes in the name have no special significance.) 649 */ 650 if (path[0] == '\0') { 651 socklen--; 652 } 653 654 #endif 655 656 mp = jbs->resolve.job.mem_pool; 657 658 jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 659 660 if (nxt_fast_path(jbs->resolve.sockaddrs != NULL)) { 661 sa = nxt_sockaddr_alloc(mp, socklen, jbs->addr.length); 662 663 if (nxt_fast_path(sa != NULL)) { 664 jbs->resolve.count = 1; 665 jbs->resolve.sockaddrs[0] = sa; 666 667 sa->u.sockaddr_un.sun_family = AF_UNIX; 668 nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length); 669 670 return NXT_OK; 671 } 672 } 673 674 return NXT_ERROR; 675 676 #else /* !(NXT_HAVE_UNIX_DOMAIN) */ 677 678 nxt_thread_log_error(jbs->resolve.log_level, 679 "unix domain socket \"%V\" is not supported", 680 &jbs->addr); 681 return NXT_ERROR; 682 683 #endif 684 } 685 686 687 static nxt_int_t 688 nxt_job_sockaddr_inet6_parse(nxt_job_sockaddr_parse_t *jbs) 689 { 690 #if (NXT_INET6) 691 u_char *p, *addr, *addr_end; 692 size_t length; 693 nxt_mp_t *mp; 694 nxt_int_t port; 695 nxt_sockaddr_t *sa; 696 struct in6_addr *in6_addr; 697 698 length = jbs->addr.length - 1; 699 addr = jbs->addr.start + 1; 700 701 addr_end = nxt_memchr(addr, ']', length); 702 703 if (addr_end == NULL) { 704 goto invalid_address; 705 } 706 707 mp = jbs->resolve.job.mem_pool; 708 709 jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 710 711 if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 712 return NXT_ERROR; 713 } 714 715 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6)); 716 717 if (nxt_slow_path(sa == NULL)) { 718 return NXT_ERROR; 719 } 720 721 jbs->resolve.count = 1; 722 jbs->resolve.sockaddrs[0] = sa; 723 724 in6_addr = &sa->u.sockaddr_in6.sin6_addr; 725 726 if (nxt_inet6_addr(in6_addr, addr, addr_end - addr) != NXT_OK) { 727 goto invalid_address; 728 } 729 730 p = addr_end + 1; 731 length = (addr + length) - p; 732 733 if (length == 0) { 734 jbs->no_port = 1; 735 port = jbs->resolve.port; 736 goto found; 737 } 738 739 if (*p == ':') { 740 port = nxt_int_parse(p + 1, length - 1); 741 742 if (port >= 1 && port <= 65535) { 743 port = htons((in_port_t) port); 744 goto found; 745 } 746 } 747 748 nxt_thread_log_error(jbs->resolve.log_level, 749 "invalid port in \"%V\"", &jbs->addr); 750 751 return NXT_ERROR; 752 753 found: 754 755 sa->u.sockaddr_in6.sin6_family = AF_INET6; 756 sa->u.sockaddr_in6.sin6_port = (in_port_t) port; 757 758 if (IN6_IS_ADDR_UNSPECIFIED(in6_addr)) { 759 jbs->wildcard = 1; 760 } 761 762 return NXT_OK; 763 764 invalid_address: 765 766 nxt_thread_log_error(jbs->resolve.log_level, 767 "invalid IPv6 address in \"%V\"", &jbs->addr); 768 return NXT_ERROR; 769 770 #else 771 772 nxt_thread_log_error(jbs->resolve.log_level, 773 "IPv6 socket \"%V\" is not supported", &jbs->addr); 774 return NXT_ERROR; 775 776 #endif 777 } 778 779 780 static nxt_int_t 781 nxt_job_sockaddr_inet_parse(nxt_job_sockaddr_parse_t *jbs) 782 { 783 u_char *p, *host; 784 size_t length; 785 nxt_mp_t *mp; 786 nxt_int_t port; 787 in_addr_t addr; 788 nxt_sockaddr_t *sa; 789 790 addr = INADDR_ANY; 791 792 length = jbs->addr.length; 793 host = jbs->addr.start; 794 795 p = nxt_memchr(host, ':', length); 796 797 if (p == NULL) { 798 799 /* single value port, address, or host name */ 800 801 port = nxt_int_parse(host, length); 802 803 if (port > 0) { 804 if (port < 1 || port > 65535) { 805 goto invalid_port; 806 } 807 808 /* "*:XX" */ 809 port = htons((in_port_t) port); 810 jbs->resolve.port = (in_port_t) port; 811 812 } else { 813 jbs->no_port = 1; 814 815 addr = nxt_inet_addr(host, length); 816 817 if (addr == INADDR_NONE) { 818 jbs->resolve.name.length = length; 819 jbs->resolve.name.start = host; 820 821 nxt_job_resolve(&jbs->resolve); 822 return NXT_AGAIN; 823 } 824 825 /* "x.x.x.x" */ 826 port = jbs->resolve.port; 827 } 828 829 } else { 830 831 /* x.x.x.x:XX or host:XX */ 832 833 p++; 834 length = (host + length) - p; 835 port = nxt_int_parse(p, length); 836 837 if (port < 1 || port > 65535) { 838 goto invalid_port; 839 } 840 841 port = htons((in_port_t) port); 842 843 length = (p - 1) - host; 844 845 if (length != 1 || host[0] != '*') { 846 addr = nxt_inet_addr(host, length); 847 848 if (addr == INADDR_NONE) { 849 jbs->resolve.name.length = length; 850 jbs->resolve.name.start = host; 851 jbs->resolve.port = (in_port_t) port; 852 853 nxt_job_resolve(&jbs->resolve); 854 return NXT_AGAIN; 855 } 856 857 /* "x.x.x.x:XX" */ 858 } 859 } 860 861 mp = jbs->resolve.job.mem_pool; 862 863 jbs->resolve.sockaddrs = nxt_mp_alloc(mp, sizeof(void *)); 864 if (nxt_slow_path(jbs->resolve.sockaddrs == NULL)) { 865 return NXT_ERROR; 866 } 867 868 sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in), 869 NXT_INET_ADDR_STR_LEN); 870 871 if (nxt_fast_path(sa != NULL)) { 872 jbs->resolve.count = 1; 873 jbs->resolve.sockaddrs[0] = sa; 874 875 jbs->wildcard = (addr == INADDR_ANY); 876 877 sa->u.sockaddr_in.sin_family = AF_INET; 878 sa->u.sockaddr_in.sin_port = (in_port_t) port; 879 sa->u.sockaddr_in.sin_addr.s_addr = addr; 880 881 return NXT_OK; 882 } 883 884 return NXT_ERROR; 885 886 invalid_port: 887 888 nxt_thread_log_error(jbs->resolve.log_level, 889 "invalid port in \"%V\"", &jbs->addr); 890 891 return NXT_ERROR; 892 } 893 894 895 in_addr_t 896 nxt_inet_addr(u_char *buf, size_t length) 897 { 898 u_char c, *end; 899 in_addr_t addr; 900 nxt_uint_t digit, octet, dots; 901 902 addr = 0; 903 octet = 0; 904 dots = 0; 905 906 end = buf + length; 907 908 while (buf < end) { 909 910 c = *buf++; 911 912 digit = c - '0'; 913 /* values below '0' become large unsigned integers */ 914 915 if (digit < 10) { 916 octet = octet * 10 + digit; 917 continue; 918 } 919 920 if (c == '.' && octet < 256) { 921 addr = (addr << 8) + octet; 922 octet = 0; 923 dots++; 924 continue; 925 } 926 927 return INADDR_NONE; 928 } 929 930 if (dots == 3 && octet < 256) { 931 addr = (addr << 8) + octet; 932 return htonl(addr); 933 } 934 935 return INADDR_NONE; 936 } 937 938 939 #if (NXT_INET6) 940 941 nxt_int_t 942 nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length) 943 { 944 u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end; 945 nxt_uint_t digit, group, nibbles, groups_left; 946 947 if (length == 0) { 948 return NXT_ERROR; 949 } 950 951 end = buf + length; 952 953 if (buf[0] == ':') { 954 buf++; 955 } 956 957 addr = in6_addr->s6_addr; 958 zero_start = NULL; 959 groups_left = 8; 960 nibbles = 0; 961 group = 0; 962 ipv4 = NULL; 963 964 while (buf < end) { 965 c = *buf++; 966 967 if (c == ':') { 968 if (nibbles != 0) { 969 ipv4 = buf; 970 971 *addr++ = (u_char) (group >> 8); 972 *addr++ = (u_char) (group & 0xff); 973 groups_left--; 974 975 if (groups_left != 0) { 976 nibbles = 0; 977 group = 0; 978 continue; 979 } 980 981 } else { 982 if (zero_start == NULL) { 983 ipv4 = buf; 984 zero_start = addr; 985 continue; 986 } 987 } 988 989 return NXT_ERROR; 990 } 991 992 if (c == '.' && nibbles != 0) { 993 994 if (groups_left < 2 || ipv4 == NULL) { 995 return NXT_ERROR; 996 } 997 998 group = nxt_inet_addr(ipv4, end - ipv4); 999 if (group == INADDR_NONE) { 1000 return NXT_ERROR; 1001 } 1002 1003 group = ntohl(group); 1004 1005 *addr++ = (u_char) ((group >> 24) & 0xff); 1006 *addr++ = (u_char) ((group >> 16) & 0xff); 1007 groups_left--; 1008 1009 /* the low 16-bit are copied below */ 1010 break; 1011 } 1012 1013 nibbles++; 1014 1015 if (nibbles > 4) { 1016 return NXT_ERROR; 1017 } 1018 1019 group <<= 4; 1020 1021 digit = c - '0'; 1022 /* values below '0' become large unsigned integers */ 1023 1024 if (digit < 10) { 1025 group += digit; 1026 continue; 1027 } 1028 1029 c |= 0x20; 1030 digit = c - 'a'; 1031 /* values below 'a' become large unsigned integers */ 1032 1033 if (digit < 6) { 1034 group += 10 + digit; 1035 continue; 1036 } 1037 1038 return NXT_ERROR; 1039 } 1040 1041 if (nibbles == 0 && zero_start == NULL) { 1042 return NXT_ERROR; 1043 } 1044 1045 *addr++ = (u_char) (group >> 8); 1046 *addr++ = (u_char) (group & 0xff); 1047 groups_left--; 1048 1049 if (groups_left != 0) { 1050 1051 if (zero_start != NULL) { 1052 1053 /* moving part before consecutive zero groups to the end */ 1054 1055 groups_left *= 2; 1056 src = addr - 1; 1057 dst = src + groups_left; 1058 1059 while (src >= zero_start) { 1060 *dst-- = *src--; 1061 } 1062 1063 nxt_memzero(zero_start, groups_left); 1064 1065 return NXT_OK; 1066 } 1067 1068 } else { 1069 if (zero_start == NULL) { 1070 return NXT_OK; 1071 } 1072 } 1073 1074 return NXT_ERROR; 1075 } 1076 1077 #endif 1078