Welcome! Log In Create A New Profile

Advanced

Re: IPv6 support in resolver

ToSHiC
July 10, 2013 01:32PM
commit 2bf37859004e3ff2b5dd9a11e1725153ca43ff32
Author: Anton Kortunov <toshic.toshic@gmail.com>
Date: Wed Jul 10 20:49:28 2013 +0400

IPv6 support in http server upstreams

Try to resolve upstream server name to IPv4 address first, then to IPv6.

diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 16e6602..df522f7 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -638,7 +638,11 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
}

ctx->name = *host;
+#if (NGX_HAVE_INET6)
+ ctx->type = NGX_RESOLVE_A_AAAA;
+#else
ctx->type = NGX_RESOLVE_A;
+#endif
ctx->handler = ngx_http_upstream_resolve_handler;
ctx->data = r;
ctx->timeout = clcf->resolver_timeout;
@@ -912,16 +916,14 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t
*ctx)

#if (NGX_DEBUG)
{
- in_addr_t addr;
+ u_char text[NGX_SOCKADDR_STRLEN];
ngx_uint_t i;

- for (i = 0; i < ctx->naddrs; i++) {
- addr = ntohl(ur->addrs[i]);
+ for (i = 0; i < ur->naddrs; i++) {
+ ngx_inet_ntop(ur->addrs[i].family, &ur->addrs[i].u, text,
NGX_SOCKADDR_STRLEN);

- ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "name was resolved to %ud.%ud.%ud.%ud",
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "name was resolved to %s", text);
}
}
#endif
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index fd4e36b..9e88a9a 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -254,7 +254,7 @@ typedef struct {
ngx_uint_t no_port; /* unsigned no_port:1 */

ngx_uint_t naddrs;
- in_addr_t *addrs;
+ ngx_ipaddr_t *addrs;

struct sockaddr *sockaddr;
socklen_t socklen;
diff --git a/src/http/ngx_http_upstream_round_robin.c
b/src/http/ngx_http_upstream_round_robin.c
index e0c6c58..cf9d6a0 100644
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -268,6 +268,9 @@
ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
size_t len;
ngx_uint_t i, n;
struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin6;
+#endif
ngx_http_upstream_rr_peers_t *peers;
ngx_http_upstream_rr_peer_data_t *rrp;

@@ -306,27 +309,52 @@
ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,

for (i = 0; i < ur->naddrs; i++) {

- len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
+ len = NGX_SOCKADDR_STRLEN;

p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
return NGX_ERROR;
}

- len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p,
NGX_INET_ADDRSTRLEN);
+ len = ngx_inet_ntop(ur->addrs[i].family, &ur->addrs[i].u, p,
NGX_SOCKADDR_STRLEN - sizeof(":65535") + 1);
len = ngx_sprintf(&p[len], ":%d", ur->port) - p;

- sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
- if (sin == NULL) {
+ switch (ur->addrs[i].family) {
+
+ case AF_INET:
+ sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
+ if (sin == NULL) {
+ return NGX_ERROR;
+ }
+
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(ur->port);
+ sin->sin_addr.s_addr = ur->addrs[i].u.v4;
+
+ peers->peer[i].sockaddr = (struct sockaddr *) sin;
+ peers->peer[i].socklen = sizeof(struct sockaddr_in);
+ break;
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in6));
+ if (sin6 == NULL) {
+ return NGX_ERROR;
+ }
+
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(ur->port);
+ sin6->sin6_addr = ur->addrs[i].u.v6;
+
+ peers->peer[i].sockaddr = (struct sockaddr *) sin6;
+ peers->peer[i].socklen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+
+ default:
return NGX_ERROR;
}

- sin->sin_family = AF_INET;
- sin->sin_port = htons(ur->port);
- sin->sin_addr.s_addr = ur->addrs[i];
-
- peers->peer[i].sockaddr = (struct sockaddr *) sin;
- peers->peer[i].socklen = sizeof(struct sockaddr_in);
peers->peer[i].name.len = len;
peers->peer[i].name.data = p;
peers->peer[i].weight = 1;



On Wed, Jul 10, 2013 at 9:29 PM, ToSHiC <toshic.toshic@gmail.com> wrote:

> commit 524dd02549575cb9ad5e95444093f6b494dc59bc
> Author: Anton Kortunov <toshic.toshic@gmail.com>
> Date: Wed Jul 10 20:43:59 2013 +0400
>
> IPv6 reverse resolve support
>
> diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
> index 567368b..06d46c1 100644
> --- a/src/core/ngx_resolver.c
> +++ b/src/core/ngx_resolver.c
> @@ -71,7 +71,7 @@ static void ngx_resolver_process_response(ngx_resolver_t
> *r, u_char *buf,
> size_t n);
> static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t
> n,
> ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans);
> -static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf,
> size_t n,
> +void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
> ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
> static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
> ngx_str_t *name, uint32_t hash);
> @@ -126,7 +126,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names,
> ngx_uint_t n)
> ngx_resolver_rbtree_insert_value);
>
> ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
> - ngx_rbtree_insert_value);
> + ngx_resolver_rbtree_insert_value);
>
> ngx_queue_init(&r->name_resend_queue);
> ngx_queue_init(&r->addr_resend_queue);
> @@ -649,17 +649,40 @@ failed:
> ngx_int_t
> ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
> {
> + uint32_t hash;
> u_char *name;
> ngx_resolver_t *r;
> ngx_resolver_node_t *rn;
>
> r = ctx->resolver;
> + rn = NULL;
> +
> + hash = ctx->addr.family;
> +
> + switch(ctx->addr.family) {
> +
> + case AF_INET:
> + ctx->addr.u.v4 = ntohl(ctx->addr.u.v4);
> + ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v4,
> sizeof(in_addr_t));
> +ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
> + "resolve addr hash: %xd, addr:%xd, family: %d", hash,
> ctx->addr.u.v4, ctx->addr.family);
> + break;
> +
> +#if (NGX_HAVE_INET6)
> + case AF_INET6:
> + ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v6, sizeof(struct
> in6_addr));
> + break;
> +#endif
>
> - ctx->addr = ntohl(ctx->addr);
> + default:
> + goto failed;
> + }
>
> /* lock addr mutex */
>
> - rn = ngx_resolver_lookup_addr(r, ctx->addr);
> + rn = ngx_resolver_lookup_addr(r, ctx->addr, hash);
> + ngx_log_error(r->log_level, r->log, 0,
> + "resolve: in resolve_addr searching, hash = %xd, rn =
> %p", hash, rn);
>
> if (rn) {
>
> @@ -714,8 +737,10 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
> goto failed;
> }
>
> - rn->node.key = ctx->addr;
> + rn->node.key = hash;
> rn->query = NULL;
> + rn->qtype = ctx->type;
> + rn->u.addr = ctx->addr;
>
> ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
> }
> @@ -788,10 +813,11 @@ failed:
> void
> ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
> {
> - in_addr_t addr;
> + uint32_t hash;
> ngx_resolver_t *r;
> ngx_resolver_ctx_t *w, **p;
> ngx_resolver_node_t *rn;
> + u_char text[NGX_SOCKADDR_STRLEN];
>
> r = ctx->resolver;
>
> @@ -806,7 +832,25 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
>
> if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
>
> - rn = ngx_resolver_lookup_addr(r, ctx->addr);
> + hash = ctx->addr.family;
> +
> + switch(ctx->addr.family) {
> +
> + case AF_INET:
> + ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v4,
> sizeof(in_addr_t));
> + break;
> +
> +#if (NGX_HAVE_INET6)
> + case AF_INET6:
> + ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v6,
> sizeof(struct in6_addr));
> + break;
> +#endif
> +
> + default:
> + goto failed;
> + }
> +
> + rn = ngx_resolver_lookup_addr(r, ctx->addr, hash);
>
> if (rn) {
> p = &rn->waiting;
> @@ -824,12 +868,12 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
> }
> }
>
> - addr = ntohl(ctx->addr);
> +failed:
> +
> + ngx_inet_ntop(ctx->addr.family, &ctx->addr.u, text,
> NGX_SOCKADDR_STRLEN);
>
> ngx_log_error(NGX_LOG_ALERT, r->log, 0,
> - "could not cancel %ud.%ud.%ud.%ud resolving",
> - (addr >> 24) & 0xff, (addr >> 16) & 0xff,
> - (addr >> 8) & 0xff, addr & 0xff);
> + "could not cancel %s resolving", text);
> }
>
> done:
> @@ -1582,13 +1626,14 @@ failed:
> }
>
>
> -static void
> +void
> ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
> ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
> {
> - char *err;
> + char *err = NULL;
> + uint32_t hash = 0;
> size_t len;
> - in_addr_t addr;
> + ngx_ipaddr_t addr;
> int32_t ttl;
> ngx_int_t digit;
> ngx_str_t name;
> @@ -1596,12 +1641,16 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
> *buf, size_t n,
> ngx_resolver_an_t *an;
> ngx_resolver_ctx_t *ctx, *next;
> ngx_resolver_node_t *rn;
> + u_char text[NGX_SOCKADDR_STRLEN];
>
> if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) {
> goto invalid_in_addr_arpa;
> }
>
> - addr = 0;
> + ngx_memzero(&addr, sizeof(ngx_ipaddr_t));
> +
> + /* Try to parse request as in-addr.arpa */
> + addr.family = AF_INET;
> i = 12;
>
> for (mask = 0; mask < 32; mask += 8) {
> @@ -1612,7 +1661,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
> *buf, size_t n,
> goto invalid_in_addr_arpa;
> }
>
> - addr += digit << mask;
> + addr.u.v4 += digit << mask;
> i += len;
> }
>
> @@ -1620,15 +1669,79 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
> *buf, size_t n,
> goto invalid_in_addr_arpa;
> }
>
> + i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
> +
> + goto found;
> +
> +invalid_in_addr_arpa:
> +
> +#if (NGX_HAVE_INET6)
> + /* Try to parse request as ip6.arpa */
> + addr.family = AF_INET6;
> + i = 12;
> +
> + for (len = 15; len < 16; len--) {
> + if (buf[i++] != 1)
> + goto invalid_arpa;
> +
> + digit = ngx_hextoi(&buf[i++], 1);
> + if (digit == NGX_ERROR || digit > 16) {
> + goto invalid_arpa;
> + }
> +
> + addr.u.v6.s6_addr[len] = digit;
> +
> + if (buf[i++] != 1)
> + goto invalid_arpa;
> +
> +
> + digit = ngx_hextoi(&buf[i++], 1);
> + if (digit == NGX_ERROR || digit > 16) {
> + goto invalid_arpa;
> + }
> +
> + addr.u.v6.s6_addr[len] += digit << 4;
> + }
> +
> + if (ngx_strcmp(&buf[i], "\3ip6\4arpa") != 0) {
> + goto invalid_arpa;
> + }
> +
> + i += sizeof("\3ip6\4arpa") + sizeof(ngx_resolver_qs_t);
> +
> +#else /* NGX_HAVE_INET6 */
> + goto invalid_arpa;
> +#endif
> +
> +found:
> +
> /* lock addr mutex */
>
> - rn = ngx_resolver_lookup_addr(r, addr);
> + hash = addr.family;
> +
> + switch(addr.family) {
> +
> + case AF_INET:
> + ngx_crc32_update(&hash, (u_char *)&addr.u.v4, sizeof(in_addr_t));
> + break;
> +
> +#if (NGX_HAVE_INET6)
> + case AF_INET6:
> + ngx_crc32_update(&hash, (u_char *)&addr.u.v6, sizeof(struct
> in6_addr));
> + break;
> +#endif
> +
> + default:
> + goto invalid;
> + }
> +
> + rn = ngx_resolver_lookup_addr(r, addr, hash);
> +
> + ngx_inet_ntop(addr.family, &addr.u, text, NGX_SOCKADDR_STRLEN);
>
> if (rn == NULL || rn->query == NULL) {
> ngx_log_error(r->log_level, r->log, 0,
> - "unexpected response for %ud.%ud.%ud.%ud",
> - (addr >> 24) & 0xff, (addr >> 16) & 0xff,
> - (addr >> 8) & 0xff, addr & 0xff);
> + "unexpected response for %s", text);
> goto failed;
> }
>
> @@ -1636,12 +1749,15 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
> *buf, size_t n,
>
> if (ident != qident) {
> ngx_log_error(r->log_level, r->log, 0,
> - "wrong ident %ui response for %ud.%ud.%ud.%ud, expect
> %ui",
> - ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff,
> - (addr >> 8) & 0xff, addr & 0xff, qident);
> + "wrong ident %ui response for %s, expect %ui",
> + ident, text, qident);
> goto failed;
> }
>
> + ngx_log_error(r->log_level, r->log, 0,
> + "code: %d, nan: %d",
> + code, nan);
> +
> if (code == 0 && nan == 0) {
> code = 3; /* NXDOMAIN */
> }
> @@ -1669,8 +1785,6 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
> *buf, size_t n,
> return;
> }
>
> - i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
> -
> if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) {
> goto short_response;
> }
> @@ -1750,10 +1864,10 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
> *buf, size_t n,
>
> return;
> -invalid_in_addr_arpa:
> +invalid_arpa:
>
> ngx_log_error(r->log_level, r->log, 0,
> - "invalid in-addr.arpa name in DNS response");
> + "invalid in-addr.arpa or ip6.arpa name in DNS
> response");
> return;
>
> short_response:
> @@ -1818,28 +1932,54 @@ ngx_resolver_lookup_name(ngx_resolver_t *r,
> ngx_str_t *name, uint32_t hash)
>
>
> static ngx_resolver_node_t *
> -ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
> +ngx_resolver_lookup_addr(ngx_resolver_t *r, ngx_ipaddr_t addr, uint32_t
> hash)
> {
> + ngx_int_t rc;
> ngx_rbtree_node_t *node, *sentinel;
> + ngx_resolver_node_t *rn;
>
> node = r->addr_rbtree.root;
> sentinel = r->addr_rbtree.sentinel;
>
> while (node != sentinel) {
>
> - if (addr < node->key) {
> + if (hash < node->key) {
> node = node->left;
> continue;
> }
>
> - if (addr > node->key) {
> + if (hash > node->key) {
> node = node->right;
> continue;
> }
>
> - /* addr == node->key */
> + /* hash == node->key */
> +
> + rn = (ngx_resolver_node_t *) node;
> +
> + rc = addr.family - rn->u.addr.family;
> +
> + if (rc == 0) {
> +
> + switch (addr.family) {
> + case AF_INET:
> + rc = ngx_memn2cmp((u_char *)&addr.u.v4, (u_char
> *)&rn->u.addr.u.v4, sizeof(in_addr_t), sizeof(in_addr_t));
> + break;
> +
> +#if (NGX_HAVE_INET6)
> + case AF_INET6:
> + rc = ngx_memn2cmp((u_char *)&addr.u.v6, (u_char
> *)&rn->u.addr.u.v6, sizeof(struct in6_addr), sizeof(struct in6_addr));
> + break;
> +#endif
> + }
> +
> + if (rc == 0) {
> + return rn;
> + }
>
> - return (ngx_resolver_node_t *) node;
> + }
> +
> + node = (rc < 0) ? node->left : node->right;
> }
>
> /* not found */
> @@ -1854,6 +1994,7 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t
> *temp,
> {
> ngx_rbtree_node_t **p;
> ngx_resolver_node_t *rn, *rn_temp;
> + ngx_int_t rc;
>
> for ( ;; ) {
>
> @@ -1870,8 +2011,29 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t
> *temp,
> rn = (ngx_resolver_node_t *) node;
> rn_temp = (ngx_resolver_node_t *) temp;
>
> - p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen,
> rn_temp->nlen)
> - < 0) ? &temp->left : &temp->right;
> + if (rn->qtype == NGX_RESOLVE_PTR) {
> + rc = rn->u.addr.family - rn_temp->u.addr.family;
> +
> + if (rc == 0) {
> +
> + switch (rn->u.addr.family) {
> + case AF_INET:
> + rc = ngx_memn2cmp((u_char *)&rn->u.addr.u.v4,
> (u_char *)&rn_temp->u.addr.u.v4, sizeof(in_addr_t), sizeof(in_addr_t));
> + break;
> +
> + #if (NGX_HAVE_INET6)
> + case AF_INET6:
> + rc = ngx_memn2cmp((u_char *)&rn->u.addr.u.v6,
> (u_char *)&rn_temp->u.addr.u.v6, sizeof(struct in6_addr), sizeof(struct
> in6_addr));
> + break;
> + #endif
> + }
> + }
> +
> + } else {
> + rc = ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen,
> rn_temp->nlen);
> + }
> +
> + p = (rc < 0) ? &temp->left : &temp->right;
> }
>
> if (*p == sentinel) {
> @@ -1989,8 +2151,6 @@ ngx_resolver_create_name_query(ngx_resolver_node_t
> *rn, ngx_resolver_ctx_t *ctx)
> }
>
>
> -/* AF_INET only */
> -
> static ngx_int_t
> ngx_resolver_create_addr_query(ngx_resolver_node_t *rn,
> ngx_resolver_ctx_t *ctx)
> {
> @@ -2001,7 +2161,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t
> *rn, ngx_resolver_ctx_t *ctx)
> ngx_resolver_query_t *query;
>
> len = sizeof(ngx_resolver_query_t)
> - + sizeof(".255.255.255.255.in-addr.arpa.") - 1
> + + NGX_PTR_QUERY_LEN
> + sizeof(ngx_resolver_qs_t);
>
> p = ngx_resolver_alloc(ctx->resolver, len);
> @@ -2028,18 +2188,50 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t
> *rn, ngx_resolver_ctx_t *ctx)
> p += sizeof(ngx_resolver_query_t);
>
> - for (n = 0; n < 32; n += 8) {
> - d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);
> - *p = (u_char) (d - &p[1]);
> - p = d;
> + switch (ctx->addr.family) {
> +
> + case AF_INET:
> + for (n = 0; n < 32; n += 8) {
> + d = ngx_sprintf(&p[1], "%ud", (ctx->addr.u.v4 >> n) & 0xff);
> + *p = (u_char) (d - &p[1]);
> + p = d;
> + }
> +
> + /* query type "PTR", IP query class */
> + ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
> +
> + rn->qlen = (u_short)
> + (p + sizeof("\7in-addr\4arpa") +
> sizeof(ngx_resolver_qs_t)
> + - rn->query);
> +
> + break;
> +
> +#if (NGX_HAVE_INET6)
> + case AF_INET6:
> + for (n = 15; n >= 0; n--) {
> + p = ngx_sprintf(p, "\1%xd\1%xd",
> + (ctx->addr.u.v6.s6_addr[n]) & 0xf,
> + (ctx->addr.u.v6.s6_addr[n] >> 4) & 0xf);
> +
> + }
> +
> + /* query type "PTR", IP query class */
> + ngx_memcpy(p, "\3ip6\4arpa\0\0\14\0\1", 18);
> +
> + rn->qlen = (u_short)
> + (p + sizeof("\3ip6\4arpa") +
> sizeof(ngx_resolver_qs_t)
> + - rn->query);
> +
> + break;
> +#endif
> +
> + default:
> + return NGX_ERROR;
> }
>
> - /* query type "PTR", IP query class */
> - ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
> +ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
> + "resolve: query %s, ident %i", (rn->query+12), ident &
> 0xffff);
>
> - rn->qlen = (u_short)
> - (p + sizeof("\7in-addr\4arpa") +
> sizeof(ngx_resolver_qs_t)
> - - rn->query);
>
> return NGX_OK;
> }
> diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
> index d2a4606..a45b244 100644
> --- a/src/core/ngx_resolver.h
> +++ b/src/core/ngx_resolver.h
> @@ -41,6 +41,11 @@
>
> #define NGX_RESOLVER_MAX_RECURSION 50
>
> +#if (NGX_HAVE_INET6)
> +#define NGX_PTR_QUERY_LEN
> (sizeof(".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.ip6.arpa.")
> - 1)
> +#else
> +#define NGX_PTR_QUERY_LEN (sizeof(".255.255.255.255.in-addr.arpa.") - 1)
> +#endif
>
> typedef struct {
> ngx_connection_t *connection;
>
>
>
> On Wed, Jul 10, 2013 at 9:24 PM, ToSHiC <toshic.toshic@gmail.com> wrote:
>
>> commit 8670b164784032b2911b3c34ac31ef52ddba5b60
>> Author: Anton Kortunov <toshic.toshic@gmail.com>
>> Date: Wed Jul 10 19:53:06 2013 +0400
>>
>> IPv6 support in resolver for forward requests
>>
>> To resolve name into IPv6 address use NGX_RESOLVE_AAAA,
>> NGX_RESOLVE_A_AAAA or NGX_RESOLVE_AAAA_A record type instead of
>> NGX_RESOLVE_A
>>
>> diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
>> index d59d0c4..567368b 100644
>> --- a/src/core/ngx_resolver.c
>> +++ b/src/core/ngx_resolver.c
>> @@ -76,7 +76,7 @@ static void ngx_resolver_process_ptr(ngx_resolver_t *r,
>> u_char *buf, size_t n,
>> static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
>> ngx_str_t *name, uint32_t hash);
>> static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
>> - in_addr_t addr);
>> + ngx_ipaddr_t addr, uint32_t hash);
>> static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
>> ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
>> static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
>> @@ -88,7 +88,7 @@ static void *ngx_resolver_calloc(ngx_resolver_t *r,
>> size_t size);
>> static void ngx_resolver_free(ngx_resolver_t *r, void *p);
>> static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
>> static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
>> -static in_addr_t *ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src,
>> +static ngx_ipaddr_t *ngx_resolver_rotate(ngx_resolver_t *r, ngx_ipaddr_t
>> *src,
>> ngx_uint_t n);
>> static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf,
>> size_t len);
>>
>> @@ -270,13 +270,27 @@ ngx_resolver_cleanup_tree(ngx_resolver_t *r,
>> ngx_rbtree_t *tree)
>> ngx_resolver_ctx_t *
>> ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
>> {
>> - in_addr_t addr;
>> + ngx_ipaddr_t addr;
>> ngx_resolver_ctx_t *ctx;
>>
>> if (temp) {
>> - addr = ngx_inet_addr(temp->name.data, temp->name.len);
>> + addr.family = 0;
>>
>> - if (addr != INADDR_NONE) {
>> +
>> + addr.u.v4 = ngx_inet_addr(temp->name.data, temp->name.len);
>> +
>> + if (addr.u.v4 != INADDR_NONE) {
>> +
>> + addr.family = AF_INET;
>> +
>> +#if (NGX_HAVE_INET6)
>> + } else if (ngx_inet6_addr(temp->name.data, temp->name.len,
>> addr.u.v6.s6_addr) == NGX_OK) {
>> +
>> + addr.family = AF_INET6;
>> +#endif
>> + }
>> +
>> + if (addr.family) {
>> temp->resolver = r;
>> temp->state = NGX_OK;
>> temp->naddrs = 1;
>> @@ -417,7 +431,7 @@ static ngx_int_t
>> ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
>> {
>> uint32_t hash;
>> - in_addr_t addr, *addrs;
>> + ngx_ipaddr_t addr, *addrs;
>> ngx_int_t rc;
>> ngx_uint_t naddrs;
>> ngx_resolver_ctx_t *next;
>> @@ -429,7 +443,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
>> ngx_resolver_ctx_t *ctx)
>>
>> if (rn) {
>>
>> - if (rn->valid >= ngx_time()) {
>> + if (rn->valid >= ngx_time()
>> +#if (NGX_HAVE_INET6)
>> + && rn->qtype != NGX_RESOLVE_RETRY
>> +#endif
>> + ) {
>>
>> ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve
>> cached");
>>
>> @@ -446,7 +464,6 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
>> ngx_resolver_ctx_t *ctx)
>> /* NGX_RESOLVE_A answer */
>>
>> if (naddrs != 1) {
>> - addr = 0;
>> addrs = ngx_resolver_rotate(r, rn->u.addrs, naddrs);
>> if (addrs == NULL) {
>> return NGX_ERROR;
>> @@ -506,6 +523,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
>> ngx_resolver_ctx_t *ctx)
>> } while (ctx);
>>
>> return NGX_OK;
>> + } else {
>> + rn->qtype = ctx->type;
>> }
>>
>> if (rn->waiting) {
>> @@ -552,6 +571,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
>> ngx_resolver_ctx_t *ctx)
>> rn->node.key = hash;
>> rn->nlen = (u_short) ctx->name.len;
>> rn->query = NULL;
>> + rn->qtype = ctx->type;
>>
>> ngx_rbtree_insert(&r->name_rbtree, &rn->node);
>> }
>> @@ -1130,6 +1150,9 @@ found:
>> switch (qtype) {
>>
>> case NGX_RESOLVE_A:
>> +#if (NGX_HAVE_INET6)
>> + case NGX_RESOLVE_AAAA:
>> +#endif
>>
>> ngx_resolver_process_a(r, buf, n, ident, code, nan,
>> i + sizeof(ngx_resolver_qs_t));
>> @@ -1178,7 +1201,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
>> *buf, size_t last,
>> size_t len;
>> int32_t ttl;
>> uint32_t hash;
>> - in_addr_t addr, *addrs;
>> + ngx_ipaddr_t addr, *addrs;
>> ngx_str_t name;
>> ngx_uint_t qtype, qident, naddrs, a, i, n, start;
>> ngx_resolver_an_t *an;
>> @@ -1212,12 +1235,57 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
>> *buf, size_t last,
>> goto failed;
>> }
>>
>> - ngx_resolver_free(r, name.data);
>> -
>> if (code == 0 && nan == 0) {
>> +
>> +#if (NGX_HAVE_INET6)
>> + /*
>> + * If it was required dual type v4|v6 resolv create one more request
>> + */
>> + if (rn->qtype == NGX_RESOLVE_A_AAAA
>> + || rn->qtype == NGX_RESOLVE_AAAA_A) {
>> +
>> + ngx_queue_remove(&rn->queue);
>> +
>> + rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
>> + rn->expire = ngx_time() + r->expire;
>> +
>> + ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
>> +
>> + ctx = rn->waiting;
>> + rn->waiting = NULL;
>> +
>> + if (ctx) {
>> + ctx->name = name;
>> +
>> + switch (rn->qtype) {
>> +
>> + case NGX_RESOLVE_A_AAAA:
>> + ctx->type = NGX_RESOLVE_AAAA;
>> + break;
>> +
>> + case NGX_RESOLVE_AAAA_A:
>> + ctx->type = NGX_RESOLVE_A;
>> + break;
>> + }
>> +
>> + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
>> + "restarting request for name %V, with type
>> %ud",
>> + &name, ctx->type);
>> +
>> + rn->qtype = NGX_RESOLVE_RETRY;
>> +
>> + (void) ngx_resolve_name_locked(r, ctx);
>> + }
>> +
>> + return;
>> + }
>> +#endif
>> +
>> code = 3; /* NXDOMAIN */
>> }
>>
>> + ngx_resolver_free(r, name.data);
>> +
>> if (code) {
>> next = rn->waiting;
>> rn->waiting = NULL;
>> @@ -1243,7 +1311,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
>> *buf, size_t last,
>>
>> i = ans;
>> naddrs = 0;
>> - addr = 0;
>> + addr.family = 0;
>> addrs = NULL;
>> cname = NULL;
>> qtype = 0;
>> @@ -1302,13 +1370,30 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
>> *buf, size_t last,
>> goto short_response;
>> }
>>
>> - addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
>> + addr.family = AF_INET;
>> + addr.u.v4 = htonl((buf[i] << 24) + (buf[i + 1] << 16)
>> + (buf[i + 2] << 8) + (buf[i + 3]));
>>
>> naddrs++;
>>
>> i += len;
>>
>> +#if (NGX_HAVE_INET6)
>> + } else if (qtype == NGX_RESOLVE_AAAA) {
>> +
>> + i += sizeof(ngx_resolver_an_t);
>> +
>> + if (i + len > last) {
>> + goto short_response;
>> + }
>> +
>> + addr.family = AF_INET6;
>> + ngx_memcpy(&addr.u.v6.s6_addr, &buf[i], 16);
>> +
>> + naddrs++;
>> +
>> + i += len;
>> +#endif
>> } else if (qtype == NGX_RESOLVE_CNAME) {
>> cname = &buf[i] + sizeof(ngx_resolver_an_t);
>> i += sizeof(ngx_resolver_an_t) + len;
>> @@ -1333,7 +1418,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
>> *buf, size_t last,
>>
>> } else {
>>
>> - addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
>> + addrs = ngx_resolver_alloc(r, naddrs * sizeof(ngx_ipaddr_t));
>> if (addrs == NULL) {
>> return;
>> }
>> @@ -1369,12 +1454,23 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
>> *buf, size_t last,
>>
>> if (qtype == NGX_RESOLVE_A) {
>>
>> - addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] <<
>> 16)
>> + addrs[n].family = AF_INET;
>> + addrs[n++].u.v4 = htonl((buf[i] << 24) + (buf[i + 1]
>> << 16)
>> + (buf[i + 2] << 8) + (buf[i +
>> 3]));
>>
>> if (n == naddrs) {
>> break;
>> }
>> +#if (NGX_HAVE_INET6)
>> + } else if (qtype == NGX_RESOLVE_AAAA) {
>> +
>> + addrs[n].family = AF_INET6;
>> + ngx_memcpy(&addrs[n++].u.v6.s6_addr, &buf[i], 16);
>> +
>> + if (n == naddrs) {
>> + break;
>> + }
>> +#endif
>> }
>>
>> i += len;
>> @@ -1383,7 +1479,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
>> *buf, size_t last,
>> rn->u.addrs = addrs;
>>
>> addrs = ngx_resolver_dup(r, rn->u.addrs,
>> - naddrs * sizeof(in_addr_t));
>> + naddrs * sizeof(ngx_ipaddr_t));
>> if (addrs == NULL) {
>> return;
>> }
>> @@ -1838,7 +1934,20 @@ ngx_resolver_create_name_query(ngx_resolver_node_t
>> *rn, ngx_resolver_ctx_t *ctx)
>> qs = (ngx_resolver_qs_t *) p;
>>
>> /* query type */
>> - qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;
>> + qs->type_hi = 0; qs->type_lo = (u_char) rn->qtype;
>> +
>> +#if (NGX_HAVE_INET6)
>> + switch (rn->qtype) {
>> +
>> + case NGX_RESOLVE_A_AAAA:
>> + qs->type_lo = NGX_RESOLVE_A;
>> + break;
>> +
>> + case NGX_RESOLVE_AAAA_A:
>> + qs->type_lo = NGX_RESOLVE_AAAA;
>> + break;
>> + }
>> +#endif
>>
>> /* IP query class */
>> qs->class_hi = 0; qs->class_lo = 1;
>> @@ -2136,13 +2245,13 @@ ngx_resolver_dup(ngx_resolver_t *r, void *src,
>> size_t size)
>> }
>>
>>
>> -static in_addr_t *
>> -ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, ngx_uint_t n)
>> +static ngx_ipaddr_t *
>> +ngx_resolver_rotate(ngx_resolver_t *r, ngx_ipaddr_t *src, ngx_uint_t n)
>> {
>> void *dst, *p;
>> ngx_uint_t j;
>>
>> - dst = ngx_resolver_alloc(r, n * sizeof(in_addr_t));
>> + dst = ngx_resolver_alloc(r, n * sizeof(ngx_ipaddr_t));
>>
>> if (dst == NULL) {
>> return dst;
>> @@ -2151,12 +2260,12 @@ ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t
>> *src, ngx_uint_t n)
>> j = ngx_random() % n;
>>
>> if (j == 0) {
>> - ngx_memcpy(dst, src, n * sizeof(in_addr_t));
>> + ngx_memcpy(dst, src, n * sizeof(ngx_ipaddr_t));
>> return dst;
>> }
>>
>> - p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(in_addr_t));
>> - ngx_memcpy(p, src, j * sizeof(in_addr_t));
>> + p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(ngx_ipaddr_t));
>> + ngx_memcpy(p, src, j * sizeof(ngx_ipaddr_t));
>>
>> return dst;
>> }
>> diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
>> index 6fd81fe..d2a4606 100644
>> --- a/src/core/ngx_resolver.h
>> +++ b/src/core/ngx_resolver.h
>> @@ -67,10 +67,11 @@ typedef struct {
>> u_short qlen;
>>
>> u_char *query;
>> + ngx_int_t qtype;
>>
>> union {
>> - in_addr_t addr;
>> - in_addr_t *addrs;
>> + ngx_ipaddr_t addr;
>> + ngx_ipaddr_t *addrs;
>> u_char *cname;
>> } u;
>>
>> @@ -130,8 +131,8 @@ struct ngx_resolver_ctx_s {
>> ngx_str_t name;
>>
>> ngx_uint_t naddrs;
>> - in_addr_t *addrs;
>> - in_addr_t addr;
>> + ngx_ipaddr_t *addrs;
>> + ngx_ipaddr_t addr;
>>
>> ngx_resolver_handler_pt handler;
>> void *data;
>>
>>
>>
>> On Wed, Jul 10, 2013 at 9:17 PM, ToSHiC <toshic.toshic@gmail.com> wrote:
>>
>>> commit 482bd2a0b6240a2b26409b9c7924ad01c814f293
>>> Author: Anton Kortunov <toshic.toshic@gmail.com>
>>> Date: Wed Jul 10 13:21:27 2013 +0400
>>>
>>> Added NGX_RESOLVE_* constants
>>>
>>> Module developers can decide how to resolve hosts relating to IPv6:
>>>
>>> NGX_RESOLVE_AAAA - try to resolve only to IPv6 address
>>> NGX_RESOLVE_AAAA_A - IPv6 is preferred (recommended by standards)
>>> NGX_RESOLVE_A_AAAA - IPv4 is preferred (better strategy nowadays)
>>>
>>> diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
>>> index ae34ca5..6fd81fe 100644
>>> --- a/src/core/ngx_resolver.h
>>> +++ b/src/core/ngx_resolver.h
>>> @@ -20,6 +20,15 @@
>>> #define NGX_RESOLVE_TXT 16
>>> #define NGX_RESOLVE_DNAME 39
>>>
>>> +#if (NGX_HAVE_INET6)
>>> +
>>> +#define NGX_RESOLVE_AAAA 28
>>> +#define NGX_RESOLVE_A_AAAA 1000
>>> +#define NGX_RESOLVE_AAAA_A 1001
>>> +#define NGX_RESOLVE_RETRY 1002
>>> +
>>> +#endif
>>> +
>>> #define NGX_RESOLVE_FORMERR 1
>>> #define NGX_RESOLVE_SERVFAIL 2
>>> #define NGX_RESOLVE_NXDOMAIN 3
>>>
>>>
>>>
>>> On Wed, Jul 10, 2013 at 9:17 PM, ToSHiC <toshic.toshic@gmail.com> wrote:
>>>
>>>> Hello,
>>>>
>>>> I've split this big patch into several small patches, taking into
>>>> account your comments. I'll send each part in separate email. Here is the
>>>> first one.
>>>>
>>>> commit 597d09e7ae9247c5466b18aa2ef3f5892e61b708
>>>> Author: Anton Kortunov <toshic.toshic@gmail.com>
>>>> Date: Wed Jul 10 13:14:52 2013 +0400
>>>>
>>>> Added new structure ngx_ipaddr_t
>>>>
>>>> This structure contains family field
>>>> and the union of ipv4/ipv6 structures in_addr_t and in6_addr.
>>>>
>>>> diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h
>>>> index 6a5a368..077ed34 100644
>>>> --- a/src/core/ngx_inet.h
>>>> +++ b/src/core/ngx_inet.h
>>>> @@ -68,6 +68,16 @@ typedef struct {
>>>>
>>>>
>>>> typedef struct {
>>>> + ngx_uint_t family;
>>>> + union {
>>>> + in_addr_t v4;
>>>> +#if (NGX_HAVE_INET6)
>>>> + struct in6_addr v6;
>>>> +#endif
>>>> + } u;
>>>> +} ngx_ipaddr_t;
>>>> +
>>>> +typedef struct {
>>>> struct sockaddr *sockaddr;
>>>> socklen_t socklen;
>>>> ngx_str_t name;
>>>>
>>>>
>>>>
>>>> On Mon, Jun 17, 2013 at 7:30 PM, Maxim Dounin <mdounin@mdounin.ru>wrote:
>>>>
>>>>> Hello!
>>>>>
>>>>> On Fri, Jun 14, 2013 at 09:44:46PM +0400, ToSHiC wrote:
>>>>>
>>>>> > Hello,
>>>>> >
>>>>> > We needed this feature in our company, I found that it is in
>>>>> milestones of
>>>>> > version 1.5 but doesn't exist yet. So I've implemented it based in
>>>>> 1.3 code
>>>>> > and merged in current 1.5 code. When I wrote this code I mostly
>>>>> cared about
>>>>> > minimum intrusion into other parts of nginx.
>>>>> >
>>>>> > IPv6 fallback logic is not a straightforward implementation of
>>>>> suggested by
>>>>> > RFC. RFC states that IPv6 resolving have priority over IPv4, and
>>>>> it's not
>>>>> > very good for Internet we have currently. With this patch you can
>>>>> specify
>>>>> > priority, and in upstream and mail modules I've set IPv4 as preferred
>>>>> > address family.
>>>>> >
>>>>> > Patch is pretty big and I hope it'll not break mailing list or mail
>>>>> clients.
>>>>>
>>>>> You may want to try to split the patch into smaller patches to
>>>>> simplify review. See also some hints here:
>>>>>
>>>>> http://nginx.org/en/docs/contributing_changes.html
>>>>>
>>>>> Some quick comments below.
>>>>>
>>>>> [...]
>>>>>
>>>>> > - addr = ntohl(ctx->addr);
>>>>> > +failed:
>>>>> > +
>>>>> > + //addr = ntohl(ctx->addr);
>>>>> > + inet_ntop(ctx->addr.family, &ctx->addr.u, text,
>>>>> > NGX_SOCKADDR_STRLEN);
>>>>> >
>>>>> > ngx_log_error(NGX_LOG_ALERT, r->log, 0,
>>>>> > - "could not cancel %ud.%ud.%ud.%ud resolving",
>>>>> > - (addr >> 24) & 0xff, (addr >> 16) & 0xff,
>>>>> > - (addr >> 8) & 0xff, addr & 0xff);
>>>>> > + "could not cancel %s resolving", text);
>>>>>
>>>>> 1. Don't use inet_ntop(), there is ngx_sock_ntop() instead.
>>>>>
>>>>> 2. Don't use C++ style ("//") comments.
>>>>>
>>>>> 3. If some data is only needed for debug logging, keep relevant
>>>>> calculations under #if (NGX_DEBUG).
>>>>>
>>>>> [...]
>>>>>
>>>>> > @@ -334,6 +362,7 @@
>>>>> > ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
>>>>> > peers->peer[i].current_weight = 0;
>>>>> > peers->peer[i].max_fails = 1;
>>>>> > peers->peer[i].fail_timeout = 10;
>>>>> > +
>>>>> > }
>>>>> > }
>>>>> >
>>>>>
>>>>> Please avoid unrelated changes.
>>>>>
>>>>> [...]
>>>>>
>>>>> --
>>>>> Maxim Dounin
>>>>> http://nginx.org/en/donation.html
>>>>>
>>>>> _______________________________________________
>>>>> nginx-devel mailing list
>>>>> nginx-devel@nginx.org
>>>>> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>>>>>
>>>>
>>>>
>>>
>>
>
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

IPv6 support in resolver

ToSHiC 1237 June 18, 2013 10:25AM

Re: IPv6 support in resolver

Maxim Dounin 734 June 18, 2013 10:25AM

Re: IPv6 support in resolver

ToSHiC 479 July 10, 2013 01:18PM

Re: IPv6 support in resolver

ToSHiC 507 July 10, 2013 01:18PM

Re: IPv6 support in resolver

ToSHiC 508 July 10, 2013 01:26PM

Re: IPv6 support in resolver

ToSHiC 558 July 10, 2013 01:30PM

Re: IPv6 support in resolver

ToSHiC 611 July 10, 2013 01:32PM

Re: IPv6 support in resolver

ToSHiC 599 July 10, 2013 01:34PM

Re: IPv6 support in resolver

Maxim Konovalov 489 July 15, 2013 09:04AM

Re: IPv6 support in resolver

Maxim Dounin 553 October 30, 2013 09:58AM

Re: IPv6 support in resolver

Ruslan Ermilov 558 November 11, 2013 11:24PM

Re: IPv6 support in resolver

Ruslan Ermilov 463 December 18, 2013 07:50AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 147
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready