diff options
Diffstat (limited to 'app/nginx/src/core/ngx_inet.c')
-rw-r--r-- | app/nginx/src/core/ngx_inet.c | 1493 |
1 files changed, 1493 insertions, 0 deletions
diff --git a/app/nginx/src/core/ngx_inet.c b/app/nginx/src/core/ngx_inet.c new file mode 100644 index 0000000..3bcd3e7 --- /dev/null +++ b/app/nginx/src/core/ngx_inet.c @@ -0,0 +1,1493 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u); +static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u); +static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u); + + +in_addr_t +ngx_inet_addr(u_char *text, size_t len) +{ + u_char *p, c; + in_addr_t addr; + ngx_uint_t octet, n; + + addr = 0; + octet = 0; + n = 0; + + for (p = text; p < text + len; p++) { + c = *p; + + if (c >= '0' && c <= '9') { + octet = octet * 10 + (c - '0'); + + if (octet > 255) { + return INADDR_NONE; + } + + continue; + } + + if (c == '.') { + addr = (addr << 8) + octet; + octet = 0; + n++; + continue; + } + + return INADDR_NONE; + } + + if (n == 3) { + addr = (addr << 8) + octet; + return htonl(addr); + } + + return INADDR_NONE; +} + + +#if (NGX_HAVE_INET6) + +ngx_int_t +ngx_inet6_addr(u_char *p, size_t len, u_char *addr) +{ + u_char c, *zero, *digit, *s, *d; + size_t len4; + ngx_uint_t n, nibbles, word; + + if (len == 0) { + return NGX_ERROR; + } + + zero = NULL; + digit = NULL; + len4 = 0; + nibbles = 0; + word = 0; + n = 8; + + if (p[0] == ':') { + p++; + len--; + } + + for (/* void */; len; len--) { + c = *p++; + + if (c == ':') { + if (nibbles) { + digit = p; + len4 = len; + *addr++ = (u_char) (word >> 8); + *addr++ = (u_char) (word & 0xff); + + if (--n) { + nibbles = 0; + word = 0; + continue; + } + + } else { + if (zero == NULL) { + digit = p; + len4 = len; + zero = addr; + continue; + } + } + + return NGX_ERROR; + } + + if (c == '.' && nibbles) { + if (n < 2 || digit == NULL) { + return NGX_ERROR; + } + + word = ngx_inet_addr(digit, len4 - 1); + if (word == INADDR_NONE) { + return NGX_ERROR; + } + + word = ntohl(word); + *addr++ = (u_char) ((word >> 24) & 0xff); + *addr++ = (u_char) ((word >> 16) & 0xff); + n--; + break; + } + + if (++nibbles > 4) { + return NGX_ERROR; + } + + if (c >= '0' && c <= '9') { + word = word * 16 + (c - '0'); + continue; + } + + c |= 0x20; + + if (c >= 'a' && c <= 'f') { + word = word * 16 + (c - 'a') + 10; + continue; + } + + return NGX_ERROR; + } + + if (nibbles == 0 && zero == NULL) { + return NGX_ERROR; + } + + *addr++ = (u_char) (word >> 8); + *addr++ = (u_char) (word & 0xff); + + if (--n) { + if (zero) { + n *= 2; + s = addr - 1; + d = s + n; + while (s >= zero) { + *d-- = *s--; + } + ngx_memzero(zero, n); + return NGX_OK; + } + + } else { + if (zero == NULL) { + return NGX_OK; + } + } + + return NGX_ERROR; +} + +#endif + + +size_t +ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, + ngx_uint_t port) +{ + u_char *p; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + size_t n; + struct sockaddr_in6 *sin6; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun; +#endif + + switch (sa->sa_family) { + + case AF_INET: + + sin = (struct sockaddr_in *) sa; + p = (u_char *) &sin->sin_addr; + + if (port) { + p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud:%d", + p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); + } else { + p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", + p[0], p[1], p[2], p[3]); + } + + return (p - text); + +#if (NGX_HAVE_INET6) + + case AF_INET6: + + sin6 = (struct sockaddr_in6 *) sa; + + n = 0; + + if (port) { + text[n++] = '['; + } + + n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len); + + if (port) { + n = ngx_sprintf(&text[1 + n], "]:%d", + ntohs(sin6->sin6_port)) - text; + } + + return n; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + + case AF_UNIX: + saun = (struct sockaddr_un *) sa; + + /* on Linux sockaddr might not include sun_path at all */ + + if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) { + p = ngx_snprintf(text, len, "unix:%Z"); + + } else { + p = ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path); + } + + /* we do not include trailing zero in address length */ + + return (p - text - 1); + +#endif + + default: + return 0; + } +} + + +size_t +ngx_inet_ntop(int family, void *addr, u_char *text, size_t len) +{ + u_char *p; + + switch (family) { + + case AF_INET: + + p = addr; + + return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", + p[0], p[1], p[2], p[3]) + - text; + +#if (NGX_HAVE_INET6) + + case AF_INET6: + return ngx_inet6_ntop(addr, text, len); + +#endif + + default: + return 0; + } +} + + +#if (NGX_HAVE_INET6) + +size_t +ngx_inet6_ntop(u_char *p, u_char *text, size_t len) +{ + u_char *dst; + size_t max, n; + ngx_uint_t i, zero, last; + + if (len < NGX_INET6_ADDRSTRLEN) { + return 0; + } + + zero = (ngx_uint_t) -1; + last = (ngx_uint_t) -1; + max = 1; + n = 0; + + for (i = 0; i < 16; i += 2) { + + if (p[i] || p[i + 1]) { + + if (max < n) { + zero = last; + max = n; + } + + n = 0; + continue; + } + + if (n++ == 0) { + last = i; + } + } + + if (max < n) { + zero = last; + max = n; + } + + dst = text; + n = 16; + + if (zero == 0) { + + if ((max == 5 && p[10] == 0xff && p[11] == 0xff) + || (max == 6) + || (max == 7 && p[14] != 0 && p[15] != 1)) + { + n = 12; + } + + *dst++ = ':'; + } + + for (i = 0; i < n; i += 2) { + + if (i == zero) { + *dst++ = ':'; + i += (max - 1) * 2; + continue; + } + + dst = ngx_sprintf(dst, "%xd", p[i] * 256 + p[i + 1]); + + if (i < 14) { + *dst++ = ':'; + } + } + + if (n == 12) { + dst = ngx_sprintf(dst, "%ud.%ud.%ud.%ud", p[12], p[13], p[14], p[15]); + } + + return dst - text; +} + +#endif + + +ngx_int_t +ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr) +{ + u_char *addr, *mask, *last; + size_t len; + ngx_int_t shift; +#if (NGX_HAVE_INET6) + ngx_int_t rc; + ngx_uint_t s, i; +#endif + + addr = text->data; + last = addr + text->len; + + mask = ngx_strlchr(addr, last, '/'); + len = (mask ? mask : last) - addr; + + cidr->u.in.addr = ngx_inet_addr(addr, len); + + if (cidr->u.in.addr != INADDR_NONE) { + cidr->family = AF_INET; + + if (mask == NULL) { + cidr->u.in.mask = 0xffffffff; + return NGX_OK; + } + +#if (NGX_HAVE_INET6) + } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) { + cidr->family = AF_INET6; + + if (mask == NULL) { + ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16); + return NGX_OK; + } + +#endif + } else { + return NGX_ERROR; + } + + mask++; + + shift = ngx_atoi(mask, last - mask); + if (shift == NGX_ERROR) { + return NGX_ERROR; + } + + switch (cidr->family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + if (shift > 128) { + return NGX_ERROR; + } + + addr = cidr->u.in6.addr.s6_addr; + mask = cidr->u.in6.mask.s6_addr; + rc = NGX_OK; + + for (i = 0; i < 16; i++) { + + s = (shift > 8) ? 8 : shift; + shift -= s; + + mask[i] = (u_char) (0xffu << (8 - s)); + + if (addr[i] != (addr[i] & mask[i])) { + rc = NGX_DONE; + addr[i] &= mask[i]; + } + } + + return rc; +#endif + + default: /* AF_INET */ + if (shift > 32) { + return NGX_ERROR; + } + + if (shift) { + cidr->u.in.mask = htonl((uint32_t) (0xffffffffu << (32 - shift))); + + } else { + /* x86 compilers use a shl instruction that shifts by modulo 32 */ + cidr->u.in.mask = 0; + } + + if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) { + return NGX_OK; + } + + cidr->u.in.addr &= cidr->u.in.mask; + + return NGX_DONE; + } +} + + +ngx_int_t +ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs) +{ +#if (NGX_HAVE_INET6) + u_char *p; +#endif + in_addr_t inaddr; + ngx_cidr_t *cidr; + ngx_uint_t family, i; +#if (NGX_HAVE_INET6) + ngx_uint_t n; + struct in6_addr *inaddr6; +#endif + +#if (NGX_SUPPRESS_WARN) + inaddr = 0; +#if (NGX_HAVE_INET6) + inaddr6 = NULL; +#endif +#endif + + family = sa->sa_family; + + if (family == AF_INET) { + inaddr = ((struct sockaddr_in *) sa)->sin_addr.s_addr; + } + +#if (NGX_HAVE_INET6) + else if (family == AF_INET6) { + inaddr6 = &((struct sockaddr_in6 *) sa)->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + family = AF_INET; + + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + inaddr = htonl(inaddr); + } + } +#endif + + for (cidr = cidrs->elts, i = 0; i < cidrs->nelts; i++) { + if (cidr[i].family != family) { + goto next; + } + + switch (family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + for (n = 0; n < 16; n++) { + if ((inaddr6->s6_addr[n] & cidr[i].u.in6.mask.s6_addr[n]) + != cidr[i].u.in6.addr.s6_addr[n]) + { + goto next; + } + } + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + break; +#endif + + default: /* AF_INET */ + if ((inaddr & cidr[i].u.in.mask) != cidr[i].u.in.addr) { + goto next; + } + break; + } + + return NGX_OK; + + next: + continue; + } + + return NGX_DECLINED; +} + + +ngx_int_t +ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len) +{ + in_addr_t inaddr; + ngx_uint_t family; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct in6_addr inaddr6; + struct sockaddr_in6 *sin6; + + /* + * prevent MSVC8 warning: + * potentially uninitialized local variable 'inaddr6' used + */ + ngx_memzero(&inaddr6, sizeof(struct in6_addr)); +#endif + + inaddr = ngx_inet_addr(text, len); + + if (inaddr != INADDR_NONE) { + family = AF_INET; + len = sizeof(struct sockaddr_in); + +#if (NGX_HAVE_INET6) + } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) { + family = AF_INET6; + len = sizeof(struct sockaddr_in6); + +#endif + } else { + return NGX_DECLINED; + } + + addr->sockaddr = ngx_pcalloc(pool, len); + if (addr->sockaddr == NULL) { + return NGX_ERROR; + } + + addr->sockaddr->sa_family = (u_char) family; + addr->socklen = len; + + switch (family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr->sockaddr; + ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr->sockaddr; + sin->sin_addr.s_addr = inaddr; + break; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, + size_t len) +{ + u_char *p, *last; + size_t plen; + ngx_int_t rc, port; + + rc = ngx_parse_addr(pool, addr, text, len); + + if (rc != NGX_DECLINED) { + return rc; + } + + last = text + len; + +#if (NGX_HAVE_INET6) + if (len && text[0] == '[') { + + p = ngx_strlchr(text, last, ']'); + + if (p == NULL || p == last - 1 || *++p != ':') { + return NGX_DECLINED; + } + + text++; + len -= 2; + + } else +#endif + + { + p = ngx_strlchr(text, last, ':'); + + if (p == NULL) { + return NGX_DECLINED; + } + } + + p++; + plen = last - p; + + port = ngx_atoi(p, plen); + + if (port < 1 || port > 65535) { + return NGX_DECLINED; + } + + len -= plen + 1; + + rc = ngx_parse_addr(pool, addr, text, len); + + if (rc != NGX_OK) { + return rc; + } + + ngx_inet_set_port(addr->sockaddr, (in_port_t) port); + + return NGX_OK; +} + + +ngx_int_t +ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) +{ + u_char *p; + size_t len; + + p = u->url.data; + len = u->url.len; + + if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { + return ngx_parse_unix_domain_url(pool, u); + } + + if (len && p[0] == '[') { + return ngx_parse_inet6_url(pool, u); + } + + return ngx_parse_inet_url(pool, u); +} + + +static ngx_int_t +ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u) +{ +#if (NGX_HAVE_UNIX_DOMAIN) + u_char *path, *uri, *last; + size_t len; + struct sockaddr_un *saun; + + len = u->url.len; + path = u->url.data; + + path += 5; + len -= 5; + + if (u->uri_part) { + + last = path + len; + uri = ngx_strlchr(path, last, ':'); + + if (uri) { + len = uri - path; + uri++; + u->uri.len = last - uri; + u->uri.data = uri; + } + } + + if (len == 0) { + u->err = "no path in the unix domain socket"; + return NGX_ERROR; + } + + u->host.len = len++; + u->host.data = path; + + if (len > sizeof(saun->sun_path)) { + u->err = "too long path in the unix domain socket"; + return NGX_ERROR; + } + + u->socklen = sizeof(struct sockaddr_un); + saun = (struct sockaddr_un *) &u->sockaddr; + saun->sun_family = AF_UNIX; + (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); + + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; + } + + saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un)); + if (saun == NULL) { + return NGX_ERROR; + } + + u->family = AF_UNIX; + u->naddrs = 1; + + saun->sun_family = AF_UNIX; + (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); + + u->addrs[0].sockaddr = (struct sockaddr *) saun; + u->addrs[0].socklen = sizeof(struct sockaddr_un); + u->addrs[0].name.len = len + 4; + u->addrs[0].name.data = u->url.data; + + return NGX_OK; + +#else + + u->err = "the unix domain sockets are not supported on this platform"; + + return NGX_ERROR; + +#endif +} + + +static ngx_int_t +ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) +{ + u_char *p, *host, *port, *last, *uri, *args; + size_t len; + ngx_int_t n; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + u->socklen = sizeof(struct sockaddr_in); + sin = (struct sockaddr_in *) &u->sockaddr; + sin->sin_family = AF_INET; + + u->family = AF_INET; + + host = u->url.data; + + last = host + u->url.len; + + port = ngx_strlchr(host, last, ':'); + + uri = ngx_strlchr(host, last, '/'); + + args = ngx_strlchr(host, last, '?'); + + if (args) { + if (uri == NULL || args < uri) { + uri = args; + } + } + + if (uri) { + if (u->listen || !u->uri_part) { + u->err = "invalid host"; + return NGX_ERROR; + } + + u->uri.len = last - uri; + u->uri.data = uri; + + last = uri; + + if (uri < port) { + port = NULL; + } + } + + if (port) { + port++; + + len = last - port; + + n = ngx_atoi(port, len); + + if (n < 1 || n > 65535) { + u->err = "invalid port"; + return NGX_ERROR; + } + + u->port = (in_port_t) n; + sin->sin_port = htons((in_port_t) n); + + u->port_text.len = len; + u->port_text.data = port; + + last = port - 1; + + } else { + if (uri == NULL) { + + if (u->listen) { + + /* test value as port only */ + + n = ngx_atoi(host, last - host); + + if (n != NGX_ERROR) { + + if (n < 1 || n > 65535) { + u->err = "invalid port"; + return NGX_ERROR; + } + + u->port = (in_port_t) n; + sin->sin_port = htons((in_port_t) n); + + u->port_text.len = last - host; + u->port_text.data = host; + + u->wildcard = 1; + + return NGX_OK; + } + } + } + + u->no_port = 1; + u->port = u->default_port; + sin->sin_port = htons(u->default_port); + } + + len = last - host; + + if (len == 0) { + u->err = "no host"; + return NGX_ERROR; + } + + u->host.len = len; + u->host.data = host; + + if (u->listen && len == 1 && *host == '*') { + sin->sin_addr.s_addr = INADDR_ANY; + u->wildcard = 1; + return NGX_OK; + } + + sin->sin_addr.s_addr = ngx_inet_addr(host, len); + + if (sin->sin_addr.s_addr != INADDR_NONE) { + + if (sin->sin_addr.s_addr == INADDR_ANY) { + u->wildcard = 1; + } + + u->naddrs = 1; + + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; + } + + sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(sin, &u->sockaddr, sizeof(struct sockaddr_in)); + + u->addrs[0].sockaddr = (struct sockaddr *) sin; + u->addrs[0].socklen = sizeof(struct sockaddr_in); + + p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); + if (p == NULL) { + return NGX_ERROR; + } + + u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", + &u->host, u->port) - p; + u->addrs[0].name.data = p; + + return NGX_OK; + } + + if (u->no_resolve) { + return NGX_OK; + } + + if (ngx_inet_resolve_host(pool, u) != NGX_OK) { + return NGX_ERROR; + } + + u->family = u->addrs[0].sockaddr->sa_family; + u->socklen = u->addrs[0].socklen; + ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen); + + switch (u->family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) &u->sockaddr; + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + u->wildcard = 1; + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) &u->sockaddr; + + if (sin->sin_addr.s_addr == INADDR_ANY) { + u->wildcard = 1; + } + + break; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) +{ +#if (NGX_HAVE_INET6) + u_char *p, *host, *port, *last, *uri; + size_t len; + ngx_int_t n; + struct sockaddr_in6 *sin6; + + u->socklen = sizeof(struct sockaddr_in6); + sin6 = (struct sockaddr_in6 *) &u->sockaddr; + sin6->sin6_family = AF_INET6; + + host = u->url.data + 1; + + last = u->url.data + u->url.len; + + p = ngx_strlchr(host, last, ']'); + + if (p == NULL) { + u->err = "invalid host"; + return NGX_ERROR; + } + + port = p + 1; + + uri = ngx_strlchr(port, last, '/'); + + if (uri) { + if (u->listen || !u->uri_part) { + u->err = "invalid host"; + return NGX_ERROR; + } + + u->uri.len = last - uri; + u->uri.data = uri; + + last = uri; + } + + if (port < last) { + if (*port != ':') { + u->err = "invalid host"; + return NGX_ERROR; + } + + port++; + + len = last - port; + + n = ngx_atoi(port, len); + + if (n < 1 || n > 65535) { + u->err = "invalid port"; + return NGX_ERROR; + } + + u->port = (in_port_t) n; + sin6->sin6_port = htons((in_port_t) n); + + u->port_text.len = len; + u->port_text.data = port; + + } else { + u->no_port = 1; + u->port = u->default_port; + sin6->sin6_port = htons(u->default_port); + } + + len = p - host; + + if (len == 0) { + u->err = "no host"; + return NGX_ERROR; + } + + u->host.len = len + 2; + u->host.data = host - 1; + + if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) { + u->err = "invalid IPv6 address"; + return NGX_ERROR; + } + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + u->wildcard = 1; + } + + u->family = AF_INET6; + u->naddrs = 1; + + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; + } + + sin6 = ngx_pcalloc(pool, sizeof(struct sockaddr_in6)); + if (sin6 == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(sin6, &u->sockaddr, sizeof(struct sockaddr_in6)); + + u->addrs[0].sockaddr = (struct sockaddr *) sin6; + u->addrs[0].socklen = sizeof(struct sockaddr_in6); + + p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); + if (p == NULL) { + return NGX_ERROR; + } + + u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", + &u->host, u->port) - p; + u->addrs[0].name.data = p; + + return NGX_OK; + +#else + + u->err = "the INET6 sockets are not supported on this platform"; + + return NGX_ERROR; + +#endif +} + + +#if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6) + +ngx_int_t +ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) +{ + u_char *p, *host; + size_t len; + in_port_t port; + ngx_uint_t i; + struct addrinfo hints, *res, *rp; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + port = htons(u->port); + + host = ngx_alloc(u->host.len + 1, pool->log); + if (host == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); + + ngx_memzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; +#ifdef AI_ADDRCONFIG + hints.ai_flags = AI_ADDRCONFIG; +#endif + + if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) { + u->err = "host not found"; + ngx_free(host); + return NGX_ERROR; + } + + ngx_free(host); + + for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) { + + switch (rp->ai_family) { + + case AF_INET: + case AF_INET6: + break; + + default: + continue; + } + + i++; + } + + if (i == 0) { + u->err = "host not found"; + goto failed; + } + + /* MP: ngx_shared_palloc() */ + + u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + goto failed; + } + + u->naddrs = i; + + i = 0; + + /* AF_INET addresses first */ + + for (rp = res; rp != NULL; rp = rp->ai_next) { + + if (rp->ai_family != AF_INET) { + continue; + } + + sin = ngx_pcalloc(pool, rp->ai_addrlen); + if (sin == NULL) { + goto failed; + } + + ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen); + + sin->sin_port = port; + + u->addrs[i].sockaddr = (struct sockaddr *) sin; + u->addrs[i].socklen = rp->ai_addrlen; + + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + goto failed; + } + + len = ngx_sock_ntop((struct sockaddr *) sin, rp->ai_addrlen, p, len, 1); + + u->addrs[i].name.len = len; + u->addrs[i].name.data = p; + + i++; + } + + for (rp = res; rp != NULL; rp = rp->ai_next) { + + if (rp->ai_family != AF_INET6) { + continue; + } + + sin6 = ngx_pcalloc(pool, rp->ai_addrlen); + if (sin6 == NULL) { + goto failed; + } + + ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen); + + sin6->sin6_port = port; + + u->addrs[i].sockaddr = (struct sockaddr *) sin6; + u->addrs[i].socklen = rp->ai_addrlen; + + len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + goto failed; + } + + len = ngx_sock_ntop((struct sockaddr *) sin6, rp->ai_addrlen, p, + len, 1); + + u->addrs[i].name.len = len; + u->addrs[i].name.data = p; + + i++; + } + + freeaddrinfo(res); + return NGX_OK; + +failed: + + freeaddrinfo(res); + return NGX_ERROR; +} + +#else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */ + +ngx_int_t +ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) +{ + u_char *p, *host; + size_t len; + in_port_t port; + in_addr_t in_addr; + ngx_uint_t i; + struct hostent *h; + struct sockaddr_in *sin; + + /* AF_INET only */ + + port = htons(u->port); + + in_addr = ngx_inet_addr(u->host.data, u->host.len); + + if (in_addr == INADDR_NONE) { + host = ngx_alloc(u->host.len + 1, pool->log); + if (host == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); + + h = gethostbyname((char *) host); + + ngx_free(host); + + if (h == NULL || h->h_addr_list[0] == NULL) { + u->err = "host not found"; + return NGX_ERROR; + } + + for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } + + /* MP: ngx_shared_palloc() */ + + u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; + } + + u->naddrs = i; + + for (i = 0; i < u->naddrs; i++) { + + sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { + return NGX_ERROR; + } + + sin->sin_family = AF_INET; + sin->sin_port = port; + sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]); + + u->addrs[i].sockaddr = (struct sockaddr *) sin; + u->addrs[i].socklen = sizeof(struct sockaddr_in); + + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + len = ngx_sock_ntop((struct sockaddr *) sin, + sizeof(struct sockaddr_in), p, len, 1); + + u->addrs[i].name.len = len; + u->addrs[i].name.data = p; + } + + } else { + + /* MP: ngx_shared_palloc() */ + + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; + } + + sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { + return NGX_ERROR; + } + + u->naddrs = 1; + + sin->sin_family = AF_INET; + sin->sin_port = port; + sin->sin_addr.s_addr = in_addr; + + u->addrs[0].sockaddr = (struct sockaddr *) sin; + u->addrs[0].socklen = sizeof(struct sockaddr_in); + + p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); + if (p == NULL) { + return NGX_ERROR; + } + + u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", + &u->host, ntohs(port)) - p; + u->addrs[0].name.data = p; + } + + return NGX_OK; +} + +#endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */ + + +ngx_int_t +ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1, + struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port) +{ + struct sockaddr_in *sin1, *sin2; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin61, *sin62; +#endif +#if (NGX_HAVE_UNIX_DOMAIN) + size_t len; + struct sockaddr_un *saun1, *saun2; +#endif + + if (sa1->sa_family != sa2->sa_family) { + return NGX_DECLINED; + } + + switch (sa1->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + + sin61 = (struct sockaddr_in6 *) sa1; + sin62 = (struct sockaddr_in6 *) sa2; + + if (cmp_port && sin61->sin6_port != sin62->sin6_port) { + return NGX_DECLINED; + } + + if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) { + return NGX_DECLINED; + } + + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + + saun1 = (struct sockaddr_un *) sa1; + saun2 = (struct sockaddr_un *) sa2; + + if (slen1 < slen2) { + len = slen1 - offsetof(struct sockaddr_un, sun_path); + + } else { + len = slen2 - offsetof(struct sockaddr_un, sun_path); + } + + if (len > sizeof(saun1->sun_path)) { + len = sizeof(saun1->sun_path); + } + + if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, len) != 0) { + return NGX_DECLINED; + } + + break; +#endif + + default: /* AF_INET */ + + sin1 = (struct sockaddr_in *) sa1; + sin2 = (struct sockaddr_in *) sa2; + + if (cmp_port && sin1->sin_port != sin2->sin_port) { + return NGX_DECLINED; + } + + if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { + return NGX_DECLINED; + } + + break; + } + + return NGX_OK; +} + + +in_port_t +ngx_inet_get_port(struct sockaddr *sa) +{ + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + return ntohs(sin6->sin6_port); +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + return 0; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + return ntohs(sin->sin_port); + } +} + + +void +ngx_inet_set_port(struct sockaddr *sa, in_port_t port) +{ + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + sin6->sin6_port = htons(port); + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + sin->sin_port = htons(port); + break; + } +} |