10Sigor@sysoev.ru
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru */
60Sigor@sysoev.ru
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru
90Sigor@sysoev.ru
100Sigor@sysoev.ru #if (NXT_INET6)
110Sigor@sysoev.ru static u_char *nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end);
120Sigor@sysoev.ru #endif
130Sigor@sysoev.ru
1499Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr);
1599Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr);
1699Sigor@sysoev.ru static nxt_sockaddr_t *nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr);
1799Sigor@sysoev.ru
180Sigor@sysoev.ru
190Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_cache_alloc(nxt_event_engine_t * engine,nxt_listen_socket_t * ls)20358Sigor@sysoev.ru nxt_sockaddr_cache_alloc(nxt_event_engine_t *engine, nxt_listen_socket_t *ls)
21337Sigor@sysoev.ru {
221266Sigor@sysoev.ru size_t size;
23358Sigor@sysoev.ru uint8_t hint;
24358Sigor@sysoev.ru nxt_sockaddr_t *sa;
25337Sigor@sysoev.ru
261266Sigor@sysoev.ru hint = NXT_EVENT_ENGINE_NO_MEM_HINT;
27337Sigor@sysoev.ru size = offsetof(nxt_sockaddr_t, u) + ls->socklen + ls->address_length;
28337Sigor@sysoev.ru
29358Sigor@sysoev.ru sa = nxt_event_engine_mem_alloc(engine, &hint, size);
30337Sigor@sysoev.ru
31337Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) {
32337Sigor@sysoev.ru /* Zero only beginning of structure up to sockaddr_un.sun_path[1]. */
33337Sigor@sysoev.ru nxt_memzero(sa, offsetof(nxt_sockaddr_t, u.sockaddr.sa_data[1]));
34337Sigor@sysoev.ru
35358Sigor@sysoev.ru sa->cache_hint = hint;
36337Sigor@sysoev.ru sa->socklen = ls->socklen;
37337Sigor@sysoev.ru sa->length = ls->address_length;
38337Sigor@sysoev.ru
39337Sigor@sysoev.ru sa->type = ls->sockaddr->type;
40337Sigor@sysoev.ru /*
41337Sigor@sysoev.ru * Set address family for unspecified Unix domain socket,
42337Sigor@sysoev.ru * because these sockaddr's are not updated by old BSD systems,
43337Sigor@sysoev.ru * see comment in nxt_conn_io_accept().
44337Sigor@sysoev.ru */
45337Sigor@sysoev.ru sa->u.sockaddr.sa_family = ls->sockaddr->u.sockaddr.sa_family;
46337Sigor@sysoev.ru }
47337Sigor@sysoev.ru
48337Sigor@sysoev.ru return sa;
49337Sigor@sysoev.ru }
50337Sigor@sysoev.ru
51337Sigor@sysoev.ru
52337Sigor@sysoev.ru void
nxt_sockaddr_cache_free(nxt_event_engine_t * engine,nxt_conn_t * c)53337Sigor@sysoev.ru nxt_sockaddr_cache_free(nxt_event_engine_t *engine, nxt_conn_t *c)
54337Sigor@sysoev.ru {
551266Sigor@sysoev.ru nxt_sockaddr_t *sa;
561266Sigor@sysoev.ru
571266Sigor@sysoev.ru sa = c->remote;
581266Sigor@sysoev.ru
591266Sigor@sysoev.ru nxt_event_engine_mem_free(engine, sa->cache_hint, sa, 0);
60337Sigor@sysoev.ru }
61337Sigor@sysoev.ru
62337Sigor@sysoev.ru
63337Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_alloc(nxt_mp_t * mp,socklen_t socklen,size_t address_length)6465Sigor@sysoev.ru nxt_sockaddr_alloc(nxt_mp_t *mp, socklen_t socklen, size_t address_length)
650Sigor@sysoev.ru {
6613Sigor@sysoev.ru size_t size;
670Sigor@sysoev.ru nxt_sockaddr_t *sa;
680Sigor@sysoev.ru
6913Sigor@sysoev.ru size = offsetof(nxt_sockaddr_t, u) + socklen + address_length;
7013Sigor@sysoev.ru
710Sigor@sysoev.ru /*
720Sigor@sysoev.ru * The current struct sockaddr's define 32-bit fields at maximum
730Sigor@sysoev.ru * and may define 64-bit AF_INET6 fields in the future. Alignment
7465Sigor@sysoev.ru * of memory allocated by nxt_mp_zalloc() is enough for these fields.
750Sigor@sysoev.ru * If 128-bit alignment will be required then nxt_mem_malloc() and
760Sigor@sysoev.ru * nxt_memzero() should be used instead.
770Sigor@sysoev.ru */
7813Sigor@sysoev.ru
7965Sigor@sysoev.ru sa = nxt_mp_zalloc(mp, size);
800Sigor@sysoev.ru
810Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) {
8213Sigor@sysoev.ru sa->socklen = socklen;
8313Sigor@sysoev.ru sa->length = address_length;
840Sigor@sysoev.ru }
850Sigor@sysoev.ru
860Sigor@sysoev.ru return sa;
870Sigor@sysoev.ru }
880Sigor@sysoev.ru
890Sigor@sysoev.ru
900Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_create(nxt_mp_t * mp,struct sockaddr * sockaddr,socklen_t length,size_t address_length)9165Sigor@sysoev.ru nxt_sockaddr_create(nxt_mp_t *mp, struct sockaddr *sockaddr, socklen_t length,
9265Sigor@sysoev.ru size_t address_length)
930Sigor@sysoev.ru {
940Sigor@sysoev.ru size_t size, copy;
950Sigor@sysoev.ru nxt_sockaddr_t *sa;
960Sigor@sysoev.ru
9710Sigor@sysoev.ru size = length;
9810Sigor@sysoev.ru copy = length;
990Sigor@sysoev.ru
1000Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1010Sigor@sysoev.ru
1020Sigor@sysoev.ru /*
1030Sigor@sysoev.ru * Unspecified Unix domain sockaddr_un form and length are very
104211Sru@nginx.com * platform depended (see comment in nxt_socket.h). Here they are
1050Sigor@sysoev.ru * normalized to the sockaddr_un with single zero byte sun_path[].
1060Sigor@sysoev.ru */
1070Sigor@sysoev.ru
1080Sigor@sysoev.ru if (size <= offsetof(struct sockaddr_un, sun_path)) {
1090Sigor@sysoev.ru /*
1100Sigor@sysoev.ru * Small socket length means a short unspecified Unix domain
1110Sigor@sysoev.ru * socket address:
1120Sigor@sysoev.ru *
1130Sigor@sysoev.ru * getsockname() and getpeername() on OpenBSD prior to 5.3
1140Sigor@sysoev.ru * return zero length and does not update a passed sockaddr
1150Sigor@sysoev.ru * buffer at all.
1160Sigor@sysoev.ru *
1170Sigor@sysoev.ru * Linux returns length equal to 2, i.e. sockaddr_un without
1180Sigor@sysoev.ru * sun_path[], unix(7):
1190Sigor@sysoev.ru *
1200Sigor@sysoev.ru * unnamed: A stream socket that has not been bound
1210Sigor@sysoev.ru * to a pathname using bind(2) has no name. Likewise,
1220Sigor@sysoev.ru * the two sockets created by socketpair(2) are unnamed.
1230Sigor@sysoev.ru * When the address of an unnamed socket is returned by
1240Sigor@sysoev.ru * getsockname(2), getpeername(2), and accept(2), its
1250Sigor@sysoev.ru * length is sizeof(sa_family_t), and sun_path should
1260Sigor@sysoev.ru * not be inspected.
1270Sigor@sysoev.ru */
1280Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1;
1290Sigor@sysoev.ru
1300Sigor@sysoev.ru #if !(NXT_LINUX)
1310Sigor@sysoev.ru
1320Sigor@sysoev.ru } else if (sockaddr->sa_family == AF_UNIX && sockaddr->sa_data[0] == '\0') {
1330Sigor@sysoev.ru /*
1340Sigor@sysoev.ru * Omit nonsignificant zeros of the unspecified Unix domain socket
1350Sigor@sysoev.ru * address. This test is disabled for Linux since Linux abstract
1360Sigor@sysoev.ru * socket address also starts with zero. However Linux unspecified
1370Sigor@sysoev.ru * Unix domain socket address is short and is handled above.
1380Sigor@sysoev.ru */
1390Sigor@sysoev.ru size = offsetof(struct sockaddr_un, sun_path) + 1;
1400Sigor@sysoev.ru copy = size;
1410Sigor@sysoev.ru
1420Sigor@sysoev.ru #endif
1430Sigor@sysoev.ru }
1440Sigor@sysoev.ru
1450Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */
1460Sigor@sysoev.ru
14713Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, size, address_length);
1480Sigor@sysoev.ru
1490Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) {
1500Sigor@sysoev.ru nxt_memcpy(&sa->u.sockaddr, sockaddr, copy);
1510Sigor@sysoev.ru
1520Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN && NXT_OPENBSD)
1530Sigor@sysoev.ru
15410Sigor@sysoev.ru if (length == 0) {
1550Sigor@sysoev.ru sa->u.sockaddr.sa_family = AF_UNIX;
1560Sigor@sysoev.ru }
1570Sigor@sysoev.ru
1580Sigor@sysoev.ru #endif
1590Sigor@sysoev.ru }
1600Sigor@sysoev.ru
1610Sigor@sysoev.ru return sa;
1620Sigor@sysoev.ru }
1630Sigor@sysoev.ru
1640Sigor@sysoev.ru
1650Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_copy(nxt_mp_t * mp,nxt_sockaddr_t * src)16665Sigor@sysoev.ru nxt_sockaddr_copy(nxt_mp_t *mp, nxt_sockaddr_t *src)
1670Sigor@sysoev.ru {
16810Sigor@sysoev.ru size_t length;
1690Sigor@sysoev.ru nxt_sockaddr_t *dst;
1700Sigor@sysoev.ru
17113Sigor@sysoev.ru length = offsetof(nxt_sockaddr_t, u) + src->socklen;
1720Sigor@sysoev.ru
17365Sigor@sysoev.ru dst = nxt_mp_alloc(mp, length);
1740Sigor@sysoev.ru
1750Sigor@sysoev.ru if (nxt_fast_path(dst != NULL)) {
17610Sigor@sysoev.ru nxt_memcpy(dst, src, length);
1770Sigor@sysoev.ru }
1780Sigor@sysoev.ru
1790Sigor@sysoev.ru return dst;
1800Sigor@sysoev.ru }
1810Sigor@sysoev.ru
1820Sigor@sysoev.ru
1830Sigor@sysoev.ru nxt_sockaddr_t *
nxt_getsockname(nxt_task_t * task,nxt_mp_t * mp,nxt_socket_t s)18465Sigor@sysoev.ru nxt_getsockname(nxt_task_t *task, nxt_mp_t *mp, nxt_socket_t s)
1850Sigor@sysoev.ru {
1860Sigor@sysoev.ru int ret;
18713Sigor@sysoev.ru size_t length;
1880Sigor@sysoev.ru socklen_t socklen;
1890Sigor@sysoev.ru nxt_sockaddr_buf_t sockaddr;
1900Sigor@sysoev.ru
1910Sigor@sysoev.ru socklen = NXT_SOCKADDR_LEN;
1920Sigor@sysoev.ru
1930Sigor@sysoev.ru ret = getsockname(s, &sockaddr.buf, &socklen);
1940Sigor@sysoev.ru
1950Sigor@sysoev.ru if (nxt_fast_path(ret == 0)) {
19613Sigor@sysoev.ru
19713Sigor@sysoev.ru switch (sockaddr.buf.sa_family) {
19813Sigor@sysoev.ru #if (NXT_INET6)
19913Sigor@sysoev.ru case AF_INET6:
2001008Szelenkov@nginx.com length = NXT_INET6_ADDR_STR_LEN;
2011008Szelenkov@nginx.com break;
20213Sigor@sysoev.ru #endif
20313Sigor@sysoev.ru
20413Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
20513Sigor@sysoev.ru case AF_UNIX:
2061008Szelenkov@nginx.com length = nxt_length("unix:") + socklen;
2072154Salx.manpages@gmail.com break;
20813Sigor@sysoev.ru #endif
20913Sigor@sysoev.ru
21013Sigor@sysoev.ru case AF_INET:
2111008Szelenkov@nginx.com length = NXT_INET_ADDR_STR_LEN;
2121008Szelenkov@nginx.com break;
21313Sigor@sysoev.ru
21413Sigor@sysoev.ru default:
2151008Szelenkov@nginx.com length = 0;
2161008Szelenkov@nginx.com break;
21713Sigor@sysoev.ru }
21813Sigor@sysoev.ru
21913Sigor@sysoev.ru return nxt_sockaddr_create(mp, &sockaddr.buf, socklen, length);
2200Sigor@sysoev.ru }
2210Sigor@sysoev.ru
22213Sigor@sysoev.ru nxt_log(task, NXT_LOG_ERR, "getsockname(%d) failed %E", s, nxt_errno);
2230Sigor@sysoev.ru
2240Sigor@sysoev.ru return NULL;
2250Sigor@sysoev.ru }
2260Sigor@sysoev.ru
2270Sigor@sysoev.ru
22813Sigor@sysoev.ru void
nxt_sockaddr_text(nxt_sockaddr_t * sa)22913Sigor@sysoev.ru nxt_sockaddr_text(nxt_sockaddr_t *sa)
2300Sigor@sysoev.ru {
23113Sigor@sysoev.ru size_t offset;
23213Sigor@sysoev.ru u_char *p, *start, *end, *octet;
23313Sigor@sysoev.ru uint32_t port;
23413Sigor@sysoev.ru
235102Sigor@sysoev.ru offset = offsetof(nxt_sockaddr_t, u) + sa->socklen;
236102Sigor@sysoev.ru sa->start = offset;
237110Sigor@sysoev.ru sa->port_start = offset;
238102Sigor@sysoev.ru
239102Sigor@sysoev.ru start = nxt_pointer_to(sa, offset);
240358Sigor@sysoev.ru end = start + sa->length;
24113Sigor@sysoev.ru
24213Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) {
24313Sigor@sysoev.ru
24413Sigor@sysoev.ru case AF_INET:
24513Sigor@sysoev.ru sa->address_start = offset;
24613Sigor@sysoev.ru
24713Sigor@sysoev.ru octet = (u_char *) &sa->u.sockaddr_in.sin_addr;
24813Sigor@sysoev.ru
24913Sigor@sysoev.ru p = nxt_sprintf(start, end, "%ud.%ud.%ud.%ud",
25013Sigor@sysoev.ru octet[0], octet[1], octet[2], octet[3]);
25113Sigor@sysoev.ru
25213Sigor@sysoev.ru sa->address_length = p - start;
253110Sigor@sysoev.ru sa->port_start += sa->address_length + 1;
2540Sigor@sysoev.ru
25513Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port;
25613Sigor@sysoev.ru
25713Sigor@sysoev.ru break;
25813Sigor@sysoev.ru
25913Sigor@sysoev.ru #if (NXT_INET6)
26013Sigor@sysoev.ru
26113Sigor@sysoev.ru case AF_INET6:
262101Sigor@sysoev.ru sa->address_start = offset + 1;
26313Sigor@sysoev.ru
26413Sigor@sysoev.ru p = start;
26513Sigor@sysoev.ru *p++ = '[';
26613Sigor@sysoev.ru
26713Sigor@sysoev.ru p = nxt_inet6_ntop(sa->u.sockaddr_in6.sin6_addr.s6_addr, p, end);
26813Sigor@sysoev.ru
26913Sigor@sysoev.ru sa->address_length = p - (start + 1);
270110Sigor@sysoev.ru sa->port_start += sa->address_length + 3;
27120Sigor@sysoev.ru
27213Sigor@sysoev.ru *p++ = ']';
2730Sigor@sysoev.ru
27413Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port;
27513Sigor@sysoev.ru
27613Sigor@sysoev.ru break;
27713Sigor@sysoev.ru
27813Sigor@sysoev.ru #endif
27913Sigor@sysoev.ru
28013Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
28113Sigor@sysoev.ru
28213Sigor@sysoev.ru case AF_UNIX:
28313Sigor@sysoev.ru sa->address_start = offset;
28413Sigor@sysoev.ru
285100Sigor@sysoev.ru p = (u_char *) sa->u.sockaddr_un.sun_path;
2860Sigor@sysoev.ru
28713Sigor@sysoev.ru #if (NXT_LINUX)
28813Sigor@sysoev.ru
28913Sigor@sysoev.ru if (p[0] == '\0') {
290493Spluknet@nginx.com size_t length;
2910Sigor@sysoev.ru
29213Sigor@sysoev.ru /* Linux abstract socket address has no trailing zero. */
29313Sigor@sysoev.ru length = sa->socklen - offsetof(struct sockaddr_un, sun_path);
29413Sigor@sysoev.ru
29513Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:@%*s", length - 1, p + 1);
29613Sigor@sysoev.ru
29713Sigor@sysoev.ru } else {
29813Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:%s", p);
29913Sigor@sysoev.ru }
30013Sigor@sysoev.ru
30113Sigor@sysoev.ru #else /* !(NXT_LINUX) */
30213Sigor@sysoev.ru
30313Sigor@sysoev.ru p = nxt_sprintf(start, end, "unix:%s", p);
3040Sigor@sysoev.ru
30513Sigor@sysoev.ru #endif
30613Sigor@sysoev.ru
30713Sigor@sysoev.ru sa->address_length = p - start;
308110Sigor@sysoev.ru sa->port_start += sa->address_length;
30913Sigor@sysoev.ru sa->length = p - start;
31013Sigor@sysoev.ru
31113Sigor@sysoev.ru return;
31213Sigor@sysoev.ru
31313Sigor@sysoev.ru #endif /* NXT_HAVE_UNIX_DOMAIN */
31413Sigor@sysoev.ru
31513Sigor@sysoev.ru default:
31613Sigor@sysoev.ru return;
3170Sigor@sysoev.ru }
3180Sigor@sysoev.ru
31913Sigor@sysoev.ru p = nxt_sprintf(p, end, ":%d", ntohs(port));
32013Sigor@sysoev.ru
32113Sigor@sysoev.ru sa->length = p - start;
3220Sigor@sysoev.ru }
3230Sigor@sysoev.ru
3240Sigor@sysoev.ru
3250Sigor@sysoev.ru uint32_t
nxt_sockaddr_port_number(nxt_sockaddr_t * sa)32613Sigor@sysoev.ru nxt_sockaddr_port_number(nxt_sockaddr_t *sa)
3270Sigor@sysoev.ru {
3280Sigor@sysoev.ru uint32_t port;
3290Sigor@sysoev.ru
3300Sigor@sysoev.ru switch (sa->u.sockaddr.sa_family) {
3310Sigor@sysoev.ru
3320Sigor@sysoev.ru #if (NXT_INET6)
3330Sigor@sysoev.ru
3340Sigor@sysoev.ru case AF_INET6:
3350Sigor@sysoev.ru port = sa->u.sockaddr_in6.sin6_port;
3360Sigor@sysoev.ru break;
3370Sigor@sysoev.ru
3380Sigor@sysoev.ru #endif
3390Sigor@sysoev.ru
3400Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
3410Sigor@sysoev.ru
3420Sigor@sysoev.ru case AF_UNIX:
3430Sigor@sysoev.ru return 0;
3440Sigor@sysoev.ru
3450Sigor@sysoev.ru #endif
3460Sigor@sysoev.ru
3470Sigor@sysoev.ru default:
3480Sigor@sysoev.ru port = sa->u.sockaddr_in.sin_port;
3490Sigor@sysoev.ru break;
3500Sigor@sysoev.ru }
3510Sigor@sysoev.ru
3520Sigor@sysoev.ru return ntohs((uint16_t) port);
3530Sigor@sysoev.ru }
3540Sigor@sysoev.ru
3550Sigor@sysoev.ru
3560Sigor@sysoev.ru nxt_bool_t
nxt_sockaddr_cmp(nxt_sockaddr_t * sa1,nxt_sockaddr_t * sa2)3570Sigor@sysoev.ru nxt_sockaddr_cmp(nxt_sockaddr_t *sa1, nxt_sockaddr_t *sa2)
3580Sigor@sysoev.ru {
35913Sigor@sysoev.ru if (sa1->socklen != sa2->socklen) {
3600Sigor@sysoev.ru return 0;
3610Sigor@sysoev.ru }
3620Sigor@sysoev.ru
3630Sigor@sysoev.ru if (sa1->type != sa2->type) {
3640Sigor@sysoev.ru return 0;
3650Sigor@sysoev.ru }
3660Sigor@sysoev.ru
3670Sigor@sysoev.ru if (sa1->u.sockaddr.sa_family != sa2->u.sockaddr.sa_family) {
3680Sigor@sysoev.ru return 0;
3690Sigor@sysoev.ru }
3700Sigor@sysoev.ru
3710Sigor@sysoev.ru /*
3720Sigor@sysoev.ru * sockaddr struct's cannot be compared in whole since kernel
3730Sigor@sysoev.ru * may fill some fields in inherited sockaddr struct's.
3740Sigor@sysoev.ru */
3750Sigor@sysoev.ru
3760Sigor@sysoev.ru switch (sa1->u.sockaddr.sa_family) {
3770Sigor@sysoev.ru
3780Sigor@sysoev.ru #if (NXT_INET6)
3790Sigor@sysoev.ru
3800Sigor@sysoev.ru case AF_INET6:
3810Sigor@sysoev.ru if (sa1->u.sockaddr_in6.sin6_port != sa2->u.sockaddr_in6.sin6_port) {
3820Sigor@sysoev.ru return 0;
3830Sigor@sysoev.ru }
3840Sigor@sysoev.ru
3852231Salx@nginx.com if (memcmp(&sa1->u.sockaddr_in6.sin6_addr,
3860Sigor@sysoev.ru &sa2->u.sockaddr_in6.sin6_addr, 16)
3870Sigor@sysoev.ru != 0)
3880Sigor@sysoev.ru {
3890Sigor@sysoev.ru return 0;
3900Sigor@sysoev.ru }
3910Sigor@sysoev.ru
3920Sigor@sysoev.ru return 1;
3930Sigor@sysoev.ru
3940Sigor@sysoev.ru #endif
3950Sigor@sysoev.ru
3960Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
3970Sigor@sysoev.ru
3980Sigor@sysoev.ru case AF_UNIX:
3990Sigor@sysoev.ru {
40010Sigor@sysoev.ru size_t length;
4010Sigor@sysoev.ru
40213Sigor@sysoev.ru length = sa1->socklen - offsetof(struct sockaddr_un, sun_path);
4030Sigor@sysoev.ru
4042231Salx@nginx.com if (memcmp(&sa1->u.sockaddr_un.sun_path,
40510Sigor@sysoev.ru &sa2->u.sockaddr_un.sun_path, length)
4060Sigor@sysoev.ru != 0)
4070Sigor@sysoev.ru {
4080Sigor@sysoev.ru return 0;
4090Sigor@sysoev.ru }
4100Sigor@sysoev.ru
4110Sigor@sysoev.ru return 1;
4120Sigor@sysoev.ru }
4130Sigor@sysoev.ru
4140Sigor@sysoev.ru #endif
4150Sigor@sysoev.ru
4160Sigor@sysoev.ru default: /* AF_INET */
4170Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_port != sa2->u.sockaddr_in.sin_port) {
4180Sigor@sysoev.ru return 0;
4190Sigor@sysoev.ru }
4200Sigor@sysoev.ru
4210Sigor@sysoev.ru if (sa1->u.sockaddr_in.sin_addr.s_addr
4220Sigor@sysoev.ru != sa2->u.sockaddr_in.sin_addr.s_addr)
4230Sigor@sysoev.ru {
4240Sigor@sysoev.ru return 0;
4250Sigor@sysoev.ru }
4260Sigor@sysoev.ru
4270Sigor@sysoev.ru return 1;
4280Sigor@sysoev.ru }
4290Sigor@sysoev.ru }
4300Sigor@sysoev.ru
4310Sigor@sysoev.ru
4320Sigor@sysoev.ru #if (NXT_INET6)
4330Sigor@sysoev.ru
4340Sigor@sysoev.ru static u_char *
nxt_inet6_ntop(u_char * addr,u_char * buf,u_char * end)4350Sigor@sysoev.ru nxt_inet6_ntop(u_char *addr, u_char *buf, u_char *end)
4360Sigor@sysoev.ru {
437101Sigor@sysoev.ru u_char *p;
438101Sigor@sysoev.ru size_t zero_groups, last_zero_groups, ipv6_bytes;
439101Sigor@sysoev.ru nxt_uint_t i, zero_start, last_zero_start;
4400Sigor@sysoev.ru
441101Sigor@sysoev.ru const size_t max_inet6_length =
442703Svbart@nginx.com nxt_length("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
443101Sigor@sysoev.ru
444101Sigor@sysoev.ru if (buf + max_inet6_length > end) {
4450Sigor@sysoev.ru return buf;
4460Sigor@sysoev.ru }
4470Sigor@sysoev.ru
4481909So.canty@f5.com zero_start = 16;
4490Sigor@sysoev.ru zero_groups = 0;
4501909So.canty@f5.com last_zero_start = 16;
4510Sigor@sysoev.ru last_zero_groups = 0;
4520Sigor@sysoev.ru
4530Sigor@sysoev.ru for (i = 0; i < 16; i += 2) {
4540Sigor@sysoev.ru
4550Sigor@sysoev.ru if (addr[i] == 0 && addr[i + 1] == 0) {
4560Sigor@sysoev.ru
4570Sigor@sysoev.ru if (last_zero_groups == 0) {
4580Sigor@sysoev.ru last_zero_start = i;
4590Sigor@sysoev.ru }
4600Sigor@sysoev.ru
4610Sigor@sysoev.ru last_zero_groups++;
4620Sigor@sysoev.ru
4630Sigor@sysoev.ru } else {
4640Sigor@sysoev.ru if (zero_groups < last_zero_groups) {
4650Sigor@sysoev.ru zero_groups = last_zero_groups;
4660Sigor@sysoev.ru zero_start = last_zero_start;
4670Sigor@sysoev.ru }
4680Sigor@sysoev.ru
4690Sigor@sysoev.ru last_zero_groups = 0;
4700Sigor@sysoev.ru }
4710Sigor@sysoev.ru }
4720Sigor@sysoev.ru
4730Sigor@sysoev.ru if (zero_groups < last_zero_groups) {
4740Sigor@sysoev.ru zero_groups = last_zero_groups;
4750Sigor@sysoev.ru zero_start = last_zero_start;
4760Sigor@sysoev.ru }
4770Sigor@sysoev.ru
4780Sigor@sysoev.ru ipv6_bytes = 16;
4790Sigor@sysoev.ru p = buf;
4800Sigor@sysoev.ru
4810Sigor@sysoev.ru if (zero_start == 0) {
4820Sigor@sysoev.ru
4830Sigor@sysoev.ru /* IPv4-mapped address */
484611Svbart@nginx.com if ((zero_groups == 5 && addr[10] == 0xFF && addr[11] == 0xFF)
4850Sigor@sysoev.ru /* IPv4-compatible address */
4860Sigor@sysoev.ru || (zero_groups == 6)
4870Sigor@sysoev.ru /* not IPv6 loopback address */
4880Sigor@sysoev.ru || (zero_groups == 7 && addr[14] != 0 && addr[15] != 1))
4890Sigor@sysoev.ru {
4900Sigor@sysoev.ru ipv6_bytes = 12;
4910Sigor@sysoev.ru }
4920Sigor@sysoev.ru
4930Sigor@sysoev.ru *p++ = ':';
4940Sigor@sysoev.ru }
4950Sigor@sysoev.ru
4960Sigor@sysoev.ru for (i = 0; i < ipv6_bytes; i += 2) {
4970Sigor@sysoev.ru
4980Sigor@sysoev.ru if (i == zero_start) {
4990Sigor@sysoev.ru /* Output maximum number of consecutive zero groups as "::". */
5000Sigor@sysoev.ru i += (zero_groups - 1) * 2;
5010Sigor@sysoev.ru *p++ = ':';
5020Sigor@sysoev.ru continue;
5030Sigor@sysoev.ru }
5040Sigor@sysoev.ru
5050Sigor@sysoev.ru p = nxt_sprintf(p, end, "%uxd", (addr[i] << 8) + addr[i + 1]);
5060Sigor@sysoev.ru
5070Sigor@sysoev.ru if (i < 14) {
5080Sigor@sysoev.ru *p++ = ':';
5090Sigor@sysoev.ru }
5100Sigor@sysoev.ru }
5110Sigor@sysoev.ru
5120Sigor@sysoev.ru if (ipv6_bytes == 12) {
5130Sigor@sysoev.ru p = nxt_sprintf(p, end, "%ud.%ud.%ud.%ud",
5140Sigor@sysoev.ru addr[12], addr[13], addr[14], addr[15]);
5150Sigor@sysoev.ru }
5160Sigor@sysoev.ru
5170Sigor@sysoev.ru return p;
5180Sigor@sysoev.ru }
5190Sigor@sysoev.ru
5200Sigor@sysoev.ru #endif
5210Sigor@sysoev.ru
5220Sigor@sysoev.ru
52399Sigor@sysoev.ru nxt_sockaddr_t *
nxt_sockaddr_parse(nxt_mp_t * mp,nxt_str_t * addr)52499Sigor@sysoev.ru nxt_sockaddr_parse(nxt_mp_t *mp, nxt_str_t *addr)
52599Sigor@sysoev.ru {
52699Sigor@sysoev.ru nxt_sockaddr_t *sa;
52799Sigor@sysoev.ru
5281935So.canty@f5.com sa = nxt_sockaddr_parse_optport(mp, addr);
5291935So.canty@f5.com
5301935So.canty@f5.com if (sa != NULL
5311935So.canty@f5.com && sa->u.sockaddr.sa_family != AF_UNIX
5321935So.canty@f5.com && nxt_sockaddr_port_number(sa) == 0)
5331935So.canty@f5.com {
5341935So.canty@f5.com nxt_thread_log_error(NXT_LOG_ERR,
5351935So.canty@f5.com "The address \"%V\" must specify a port.", addr);
5361935So.canty@f5.com return NULL;
5371935So.canty@f5.com }
5381935So.canty@f5.com
5391935So.canty@f5.com return sa;
5401935So.canty@f5.com }
5411935So.canty@f5.com
5421935So.canty@f5.com
5431935So.canty@f5.com nxt_sockaddr_t *
nxt_sockaddr_parse_optport(nxt_mp_t * mp,nxt_str_t * addr)5441935So.canty@f5.com nxt_sockaddr_parse_optport(nxt_mp_t *mp, nxt_str_t *addr)
5451935So.canty@f5.com {
5461935So.canty@f5.com nxt_sockaddr_t *sa;
5471935So.canty@f5.com
5481935So.canty@f5.com if (addr->length == 0) {
5491935So.canty@f5.com nxt_thread_log_error(NXT_LOG_ERR, "socket address cannot be empty");
5501935So.canty@f5.com return NULL;
5511935So.canty@f5.com }
5521935So.canty@f5.com
5532231Salx@nginx.com if (addr->length > 6 && memcmp(addr->start, "unix:", 5) == 0) {
55499Sigor@sysoev.ru sa = nxt_sockaddr_unix_parse(mp, addr);
55599Sigor@sysoev.ru
5561935So.canty@f5.com } else if (addr->start[0] == '[' || nxt_inet6_probe(addr)) {
55799Sigor@sysoev.ru sa = nxt_sockaddr_inet6_parse(mp, addr);
55899Sigor@sysoev.ru
55999Sigor@sysoev.ru } else {
56099Sigor@sysoev.ru sa = nxt_sockaddr_inet_parse(mp, addr);
56199Sigor@sysoev.ru }
56299Sigor@sysoev.ru
56399Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) {
56499Sigor@sysoev.ru nxt_sockaddr_text(sa);
56599Sigor@sysoev.ru }
56699Sigor@sysoev.ru
56799Sigor@sysoev.ru return sa;
56899Sigor@sysoev.ru }
56999Sigor@sysoev.ru
57099Sigor@sysoev.ru
57199Sigor@sysoev.ru static nxt_sockaddr_t *
nxt_sockaddr_unix_parse(nxt_mp_t * mp,nxt_str_t * addr)57299Sigor@sysoev.ru nxt_sockaddr_unix_parse(nxt_mp_t *mp, nxt_str_t *addr)
57399Sigor@sysoev.ru {
57499Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
57599Sigor@sysoev.ru size_t length, socklen;
57699Sigor@sysoev.ru u_char *path;
57799Sigor@sysoev.ru nxt_sockaddr_t *sa;
57899Sigor@sysoev.ru
57999Sigor@sysoev.ru /*
58099Sigor@sysoev.ru * Actual sockaddr_un length can be lesser or even larger than defined
581211Sru@nginx.com * struct sockaddr_un length (see comment in nxt_socket.h). So
58299Sigor@sysoev.ru * limit maximum Unix domain socket address length by defined sun_path[]
58399Sigor@sysoev.ru * length because some OSes accept addresses twice larger than defined
58499Sigor@sysoev.ru * struct sockaddr_un. Also reserve space for a trailing zero to avoid
58599Sigor@sysoev.ru * ambiguity, since many OSes accept Unix domain socket addresses
58699Sigor@sysoev.ru * without a trailing zero.
58799Sigor@sysoev.ru */
58899Sigor@sysoev.ru const size_t max_len = sizeof(struct sockaddr_un)
58999Sigor@sysoev.ru - offsetof(struct sockaddr_un, sun_path) - 1;
59099Sigor@sysoev.ru
59199Sigor@sysoev.ru /* Cutting "unix:". */
59299Sigor@sysoev.ru length = addr->length - 5;
59399Sigor@sysoev.ru path = addr->start + 5;
59499Sigor@sysoev.ru
59599Sigor@sysoev.ru if (length > max_len) {
59699Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR,
59799Sigor@sysoev.ru "unix domain socket \"%V\" name is too long",
59899Sigor@sysoev.ru addr);
59999Sigor@sysoev.ru return NULL;
60099Sigor@sysoev.ru }
60199Sigor@sysoev.ru
60299Sigor@sysoev.ru socklen = offsetof(struct sockaddr_un, sun_path) + length + 1;
60399Sigor@sysoev.ru
60499Sigor@sysoev.ru /*
60599Sigor@sysoev.ru * Linux unix(7):
60699Sigor@sysoev.ru *
60799Sigor@sysoev.ru * abstract: an abstract socket address is distinguished by the fact
60899Sigor@sysoev.ru * that sun_path[0] is a null byte ('\0'). The socket's address in
60999Sigor@sysoev.ru * this namespace is given by the additional bytes in sun_path that
61099Sigor@sysoev.ru * are covered by the specified length of the address structure.
61199Sigor@sysoev.ru * (Null bytes in the name have no special significance.)
61299Sigor@sysoev.ru */
61399Sigor@sysoev.ru if (path[0] == '@') {
61499Sigor@sysoev.ru path[0] = '\0';
61599Sigor@sysoev.ru socklen--;
6162181Salx.manpages@gmail.com #if !(NXT_LINUX)
6172181Salx.manpages@gmail.com nxt_thread_log_error(NXT_LOG_ERR,
6182181Salx.manpages@gmail.com "abstract unix domain sockets are not supported");
6192181Salx.manpages@gmail.com return NULL;
6202181Salx.manpages@gmail.com #endif
62199Sigor@sysoev.ru }
62299Sigor@sysoev.ru
62399Sigor@sysoev.ru sa = nxt_sockaddr_alloc(mp, socklen, addr->length);
62499Sigor@sysoev.ru
62599Sigor@sysoev.ru if (nxt_fast_path(sa != NULL)) {
62699Sigor@sysoev.ru sa->u.sockaddr_un.sun_family = AF_UNIX;
62799Sigor@sysoev.ru nxt_memcpy(sa->u.sockaddr_un.sun_path, path, length);
62899Sigor@sysoev.ru }
62999Sigor@sysoev.ru
63099Sigor@sysoev.ru return sa;
63199Sigor@sysoev.ru
63299Sigor@sysoev.ru #else /* !(NXT_HAVE_UNIX_DOMAIN) */
63399Sigor@sysoev.ru
63499Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR,
63599Sigor@sysoev.ru "unix domain socket \"%V\" is not supported", addr);
63699Sigor@sysoev.ru
63799Sigor@sysoev.ru return NULL;
63899Sigor@sysoev.ru
63999Sigor@sysoev.ru #endif
64099Sigor@sysoev.ru }
64199Sigor@sysoev.ru
64299Sigor@sysoev.ru
64399Sigor@sysoev.ru static nxt_sockaddr_t *
nxt_sockaddr_inet6_parse(nxt_mp_t * mp,nxt_str_t * addr)64499Sigor@sysoev.ru nxt_sockaddr_inet6_parse(nxt_mp_t *mp, nxt_str_t *addr)
64599Sigor@sysoev.ru {
64699Sigor@sysoev.ru #if (NXT_INET6)
64799Sigor@sysoev.ru u_char *p, *start, *end;
64899Sigor@sysoev.ru size_t length;
64999Sigor@sysoev.ru nxt_int_t ret, port;
65099Sigor@sysoev.ru nxt_sockaddr_t *sa;
65199Sigor@sysoev.ru
6521935So.canty@f5.com if (addr->start[0] == '[') {
6531935So.canty@f5.com length = addr->length - 1;
6541935So.canty@f5.com start = addr->start + 1;
65599Sigor@sysoev.ru
656*2232Salx@nginx.com end = memchr(start, ']', length);
6571935So.canty@f5.com if (nxt_slow_path(end == NULL)) {
65899Sigor@sysoev.ru return NULL;
65999Sigor@sysoev.ru }
66099Sigor@sysoev.ru
6611935So.canty@f5.com p = end + 1;
66299Sigor@sysoev.ru
6631935So.canty@f5.com } else {
6641935So.canty@f5.com length = addr->length;
6651935So.canty@f5.com start = addr->start;
6661935So.canty@f5.com end = addr->start + addr->length;
6671935So.canty@f5.com p = NULL;
6681935So.canty@f5.com }
66999Sigor@sysoev.ru
6701935So.canty@f5.com port = 0;
67199Sigor@sysoev.ru
6721935So.canty@f5.com if (p != NULL) {
6731935So.canty@f5.com length = (start + length) - p;
67499Sigor@sysoev.ru
6751935So.canty@f5.com if (length < 2 || *p != ':') {
6761935So.canty@f5.com nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"",
6771935So.canty@f5.com addr);
6781935So.canty@f5.com return NULL;
6791935So.canty@f5.com }
68099Sigor@sysoev.ru
6811935So.canty@f5.com port = nxt_int_parse(p + 1, length - 1);
6821935So.canty@f5.com
6831935So.canty@f5.com if (port < 1 || port > 65535) {
68499Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
68599Sigor@sysoev.ru return NULL;
68699Sigor@sysoev.ru }
68799Sigor@sysoev.ru }
68899Sigor@sysoev.ru
6891935So.canty@f5.com sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in6),
6901935So.canty@f5.com NXT_INET6_ADDR_STR_LEN);
6911935So.canty@f5.com if (nxt_slow_path(sa == NULL)) {
6921935So.canty@f5.com return NULL;
6931935So.canty@f5.com }
69499Sigor@sysoev.ru
6951935So.canty@f5.com ret = nxt_inet6_addr(&sa->u.sockaddr_in6.sin6_addr, start, end - start);
6961935So.canty@f5.com if (nxt_slow_path(ret != NXT_OK)) {
6971935So.canty@f5.com nxt_thread_log_error(NXT_LOG_ERR, "invalid IPv6 address in \"%V\"",
6981935So.canty@f5.com addr);
6991935So.canty@f5.com return NULL;
7001935So.canty@f5.com }
7011935So.canty@f5.com
7021935So.canty@f5.com sa->u.sockaddr_in6.sin6_family = AF_INET6;
7031935So.canty@f5.com sa->u.sockaddr_in6.sin6_port = htons((in_port_t) port);
7041935So.canty@f5.com
7051935So.canty@f5.com return sa;
70699Sigor@sysoev.ru
70799Sigor@sysoev.ru #else /* !(NXT_INET6) */
70899Sigor@sysoev.ru
70999Sigor@sysoev.ru nxt_thread_log_error(NXT_LOG_ERR, "IPv6 socket \"%V\" is not supported",
71099Sigor@sysoev.ru addr);
71199Sigor@sysoev.ru return NULL;
71299Sigor@sysoev.ru
71399Sigor@sysoev.ru #endif
71499Sigor@sysoev.ru }
71599Sigor@sysoev.ru
71699Sigor@sysoev.ru
71799Sigor@sysoev.ru static nxt_sockaddr_t *
nxt_sockaddr_inet_parse(nxt_mp_t * mp,nxt_str_t * addr)71899Sigor@sysoev.ru nxt_sockaddr_inet_parse(nxt_mp_t *mp, nxt_str_t *addr)
71999Sigor@sysoev.ru {
72099Sigor@sysoev.ru u_char *p;
72199Sigor@sysoev.ru size_t length;
72299Sigor@sysoev.ru nxt_int_t port;
72399Sigor@sysoev.ru in_addr_t inaddr;
72499Sigor@sysoev.ru nxt_sockaddr_t *sa;
72599Sigor@sysoev.ru
726*2232Salx@nginx.com p = memchr(addr->start, ':', addr->length);
72799Sigor@sysoev.ru
7281935So.canty@f5.com if (p == NULL) {
7291935So.canty@f5.com length = addr->length;
73099Sigor@sysoev.ru
7311935So.canty@f5.com } else {
7321935So.canty@f5.com length = p - addr->start;
7331935So.canty@f5.com }
73499Sigor@sysoev.ru
7351935So.canty@f5.com inaddr = INADDR_ANY;
73699Sigor@sysoev.ru
7371935So.canty@f5.com if (length != 1 || addr->start[0] != '*') {
7381935So.canty@f5.com inaddr = nxt_inet_addr(addr->start, length);
7391935So.canty@f5.com if (nxt_slow_path(inaddr == INADDR_NONE)) {
7401935So.canty@f5.com nxt_thread_log_error(NXT_LOG_ERR, "invalid address \"%V\"", addr);
7411935So.canty@f5.com return NULL;
74299Sigor@sysoev.ru }
74399Sigor@sysoev.ru }
74499Sigor@sysoev.ru
7451935So.canty@f5.com port = 0;
7461935So.canty@f5.com
7471935So.canty@f5.com if (p != NULL) {
7481935So.canty@f5.com p++;
7491935So.canty@f5.com length = (addr->start + addr->length) - p;
7501935So.canty@f5.com
7511935So.canty@f5.com port = nxt_int_parse(p, length);
75299Sigor@sysoev.ru
7531935So.canty@f5.com if (port < 1 || port > 65535) {
7541935So.canty@f5.com nxt_thread_log_error(NXT_LOG_ERR, "invalid port in \"%V\"", addr);
7551935So.canty@f5.com return NULL;
7561935So.canty@f5.com }
7571935So.canty@f5.com }
7581935So.canty@f5.com
7591935So.canty@f5.com sa = nxt_sockaddr_alloc(mp, sizeof(struct sockaddr_in),
7601935So.canty@f5.com NXT_INET_ADDR_STR_LEN);
7611935So.canty@f5.com if (nxt_slow_path(sa == NULL)) {
7621935So.canty@f5.com return NULL;
7631935So.canty@f5.com }
7641935So.canty@f5.com
7651935So.canty@f5.com sa->u.sockaddr_in.sin_family = AF_INET;
7661935So.canty@f5.com sa->u.sockaddr_in.sin_addr.s_addr = inaddr;
7671935So.canty@f5.com sa->u.sockaddr_in.sin_port = htons((in_port_t) port);
7681935So.canty@f5.com
7691935So.canty@f5.com return sa;
77099Sigor@sysoev.ru }
77199Sigor@sysoev.ru
77299Sigor@sysoev.ru
7730Sigor@sysoev.ru in_addr_t
nxt_inet_addr(u_char * buf,size_t length)77410Sigor@sysoev.ru nxt_inet_addr(u_char *buf, size_t length)
7750Sigor@sysoev.ru {
7760Sigor@sysoev.ru u_char c, *end;
7770Sigor@sysoev.ru in_addr_t addr;
7780Sigor@sysoev.ru nxt_uint_t digit, octet, dots;
7790Sigor@sysoev.ru
7801324Saxel.duch@nginx.com if (nxt_slow_path(*(buf + length - 1) == '.')) {
7811324Saxel.duch@nginx.com return INADDR_NONE;
7821324Saxel.duch@nginx.com }
7831324Saxel.duch@nginx.com
7840Sigor@sysoev.ru addr = 0;
7850Sigor@sysoev.ru octet = 0;
7860Sigor@sysoev.ru dots = 0;
7870Sigor@sysoev.ru
78810Sigor@sysoev.ru end = buf + length;
7890Sigor@sysoev.ru
7900Sigor@sysoev.ru while (buf < end) {
7910Sigor@sysoev.ru
7920Sigor@sysoev.ru c = *buf++;
7930Sigor@sysoev.ru
7940Sigor@sysoev.ru digit = c - '0';
7950Sigor@sysoev.ru /* values below '0' become large unsigned integers */
7960Sigor@sysoev.ru
7970Sigor@sysoev.ru if (digit < 10) {
7980Sigor@sysoev.ru octet = octet * 10 + digit;
7990Sigor@sysoev.ru continue;
8000Sigor@sysoev.ru }
8010Sigor@sysoev.ru
8020Sigor@sysoev.ru if (c == '.' && octet < 256) {
8030Sigor@sysoev.ru addr = (addr << 8) + octet;
8040Sigor@sysoev.ru octet = 0;
8050Sigor@sysoev.ru dots++;
8060Sigor@sysoev.ru continue;
8070Sigor@sysoev.ru }
8080Sigor@sysoev.ru
8090Sigor@sysoev.ru return INADDR_NONE;
8100Sigor@sysoev.ru }
8110Sigor@sysoev.ru
8120Sigor@sysoev.ru if (dots == 3 && octet < 256) {
8130Sigor@sysoev.ru addr = (addr << 8) + octet;
8140Sigor@sysoev.ru return htonl(addr);
8150Sigor@sysoev.ru }
8160Sigor@sysoev.ru
8170Sigor@sysoev.ru return INADDR_NONE;
8180Sigor@sysoev.ru }
8190Sigor@sysoev.ru
8200Sigor@sysoev.ru
8210Sigor@sysoev.ru #if (NXT_INET6)
8220Sigor@sysoev.ru
8230Sigor@sysoev.ru nxt_int_t
nxt_inet6_addr(struct in6_addr * in6_addr,u_char * buf,size_t length)82410Sigor@sysoev.ru nxt_inet6_addr(struct in6_addr *in6_addr, u_char *buf, size_t length)
8250Sigor@sysoev.ru {
8260Sigor@sysoev.ru u_char c, *addr, *zero_start, *ipv4, *dst, *src, *end;
8270Sigor@sysoev.ru nxt_uint_t digit, group, nibbles, groups_left;
8280Sigor@sysoev.ru
82910Sigor@sysoev.ru if (length == 0) {
8300Sigor@sysoev.ru return NXT_ERROR;
8310Sigor@sysoev.ru }
8320Sigor@sysoev.ru
83310Sigor@sysoev.ru end = buf + length;
8340Sigor@sysoev.ru
8350Sigor@sysoev.ru if (buf[0] == ':') {
8360Sigor@sysoev.ru buf++;
8370Sigor@sysoev.ru }
8380Sigor@sysoev.ru
8390Sigor@sysoev.ru addr = in6_addr->s6_addr;
8400Sigor@sysoev.ru zero_start = NULL;
8410Sigor@sysoev.ru groups_left = 8;
8420Sigor@sysoev.ru nibbles = 0;
8430Sigor@sysoev.ru group = 0;
8440Sigor@sysoev.ru ipv4 = NULL;
8450Sigor@sysoev.ru
8460Sigor@sysoev.ru while (buf < end) {
8470Sigor@sysoev.ru c = *buf++;
8480Sigor@sysoev.ru
8490Sigor@sysoev.ru if (c == ':') {
8500Sigor@sysoev.ru if (nibbles != 0) {
8510Sigor@sysoev.ru ipv4 = buf;
8520Sigor@sysoev.ru
8530Sigor@sysoev.ru *addr++ = (u_char) (group >> 8);
854611Svbart@nginx.com *addr++ = (u_char) (group & 0xFF);
8550Sigor@sysoev.ru groups_left--;
8560Sigor@sysoev.ru
8570Sigor@sysoev.ru if (groups_left != 0) {
8580Sigor@sysoev.ru nibbles = 0;
8590Sigor@sysoev.ru group = 0;
8600Sigor@sysoev.ru continue;
8610Sigor@sysoev.ru }
8620Sigor@sysoev.ru
8630Sigor@sysoev.ru } else {
8640Sigor@sysoev.ru if (zero_start == NULL) {
8650Sigor@sysoev.ru ipv4 = buf;
8660Sigor@sysoev.ru zero_start = addr;
8670Sigor@sysoev.ru continue;
8680Sigor@sysoev.ru }
8690Sigor@sysoev.ru }
8700Sigor@sysoev.ru
8710Sigor@sysoev.ru return NXT_ERROR;
8720Sigor@sysoev.ru }
8730Sigor@sysoev.ru
8740Sigor@sysoev.ru if (c == '.' && nibbles != 0) {
8750Sigor@sysoev.ru
8760Sigor@sysoev.ru if (groups_left < 2 || ipv4 == NULL) {
8770Sigor@sysoev.ru return NXT_ERROR;
8780Sigor@sysoev.ru }
8790Sigor@sysoev.ru
8800Sigor@sysoev.ru group = nxt_inet_addr(ipv4, end - ipv4);
8810Sigor@sysoev.ru if (group == INADDR_NONE) {
8820Sigor@sysoev.ru return NXT_ERROR;
8830Sigor@sysoev.ru }
8840Sigor@sysoev.ru
8850Sigor@sysoev.ru group = ntohl(group);
8860Sigor@sysoev.ru
887611Svbart@nginx.com *addr++ = (u_char) ((group >> 24) & 0xFF);
888611Svbart@nginx.com *addr++ = (u_char) ((group >> 16) & 0xFF);
8890Sigor@sysoev.ru groups_left--;
8900Sigor@sysoev.ru
8910Sigor@sysoev.ru /* the low 16-bit are copied below */
8920Sigor@sysoev.ru break;
8930Sigor@sysoev.ru }
8940Sigor@sysoev.ru
8950Sigor@sysoev.ru nibbles++;
8960Sigor@sysoev.ru
8970Sigor@sysoev.ru if (nibbles > 4) {
8980Sigor@sysoev.ru return NXT_ERROR;
8990Sigor@sysoev.ru }
9000Sigor@sysoev.ru
9010Sigor@sysoev.ru group <<= 4;
9020Sigor@sysoev.ru
9030Sigor@sysoev.ru digit = c - '0';
9040Sigor@sysoev.ru /* values below '0' become large unsigned integers */
9050Sigor@sysoev.ru
9060Sigor@sysoev.ru if (digit < 10) {
9070Sigor@sysoev.ru group += digit;
9080Sigor@sysoev.ru continue;
9090Sigor@sysoev.ru }
9100Sigor@sysoev.ru
9110Sigor@sysoev.ru c |= 0x20;
9120Sigor@sysoev.ru digit = c - 'a';
9130Sigor@sysoev.ru /* values below 'a' become large unsigned integers */
9140Sigor@sysoev.ru
9150Sigor@sysoev.ru if (digit < 6) {
9160Sigor@sysoev.ru group += 10 + digit;
9170Sigor@sysoev.ru continue;
9180Sigor@sysoev.ru }
9190Sigor@sysoev.ru
9200Sigor@sysoev.ru return NXT_ERROR;
9210Sigor@sysoev.ru }
9220Sigor@sysoev.ru
9230Sigor@sysoev.ru if (nibbles == 0 && zero_start == NULL) {
9240Sigor@sysoev.ru return NXT_ERROR;
9250Sigor@sysoev.ru }
9260Sigor@sysoev.ru
9270Sigor@sysoev.ru *addr++ = (u_char) (group >> 8);
928611Svbart@nginx.com *addr++ = (u_char) (group & 0xFF);
9290Sigor@sysoev.ru groups_left--;
9300Sigor@sysoev.ru
9310Sigor@sysoev.ru if (groups_left != 0) {
9320Sigor@sysoev.ru
9330Sigor@sysoev.ru if (zero_start != NULL) {
9340Sigor@sysoev.ru
9350Sigor@sysoev.ru /* moving part before consecutive zero groups to the end */
9360Sigor@sysoev.ru
9370Sigor@sysoev.ru groups_left *= 2;
9380Sigor@sysoev.ru src = addr - 1;
9390Sigor@sysoev.ru dst = src + groups_left;
9400Sigor@sysoev.ru
9410Sigor@sysoev.ru while (src >= zero_start) {
9420Sigor@sysoev.ru *dst-- = *src--;
9430Sigor@sysoev.ru }
9440Sigor@sysoev.ru
9450Sigor@sysoev.ru nxt_memzero(zero_start, groups_left);
9460Sigor@sysoev.ru
9470Sigor@sysoev.ru return NXT_OK;
9480Sigor@sysoev.ru }
9490Sigor@sysoev.ru
9500Sigor@sysoev.ru } else {
9510Sigor@sysoev.ru if (zero_start == NULL) {
9520Sigor@sysoev.ru return NXT_OK;
9530Sigor@sysoev.ru }
9540Sigor@sysoev.ru }
9550Sigor@sysoev.ru
9560Sigor@sysoev.ru return NXT_ERROR;
9570Sigor@sysoev.ru }
9580Sigor@sysoev.ru
9590Sigor@sysoev.ru #endif
9601935So.canty@f5.com
9611935So.canty@f5.com
9621935So.canty@f5.com nxt_bool_t
nxt_inet6_probe(nxt_str_t * str)9631935So.canty@f5.com nxt_inet6_probe(nxt_str_t *str)
9641935So.canty@f5.com {
9651935So.canty@f5.com u_char *colon, *end;
9661935So.canty@f5.com
967*2232Salx@nginx.com colon = memchr(str->start, ':', str->length);
9681935So.canty@f5.com
9691935So.canty@f5.com if (colon != NULL) {
9701935So.canty@f5.com end = str->start + str->length;
971*2232Salx@nginx.com colon = memchr(colon + 1, ':', end - (colon + 1));
9721935So.canty@f5.com }
9731935So.canty@f5.com
9741935So.canty@f5.com return (colon != NULL);
9751935So.canty@f5.com }
976