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