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