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