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