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