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