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