details: http://hg.nginx.org/nginx/rev/5a16d40c63de branches: changeset: 6367:5a16d40c63de user: Roman Arutyunyan <a...@nginx.com> date: Thu Jan 28 15:28:20 2016 +0300 description: Resolver: TCP support.
Resend DNS query over TCP once UDP response came truncated. diffstat: src/core/ngx_resolver.c | 593 +++++++++++++++++++++++++++++++++++++++++++---- src/core/ngx_resolver.h | 17 +- 2 files changed, 554 insertions(+), 56 deletions(-) diffs (truncated from 834 to 300 lines): diff -r 2e5c027f2a98 -r 5a16d40c63de src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c Thu Jan 28 15:28:20 2016 +0300 +++ b/src/core/ngx_resolver.c Thu Jan 28 15:28:20 2016 +0300 @@ -12,6 +12,9 @@ #define NGX_RESOLVER_UDP_SIZE 4096 +#define NGX_RESOLVER_TCP_RSIZE (2 + 65535) +#define NGX_RESOLVER_TCP_WSIZE 8192 + typedef struct { u_char ident_hi; @@ -54,6 +57,7 @@ typedef struct { ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); +ngx_int_t ngx_tcp_connect(ngx_resolver_connection_t *rec); static void ngx_resolver_cleanup(void *data); @@ -64,6 +68,10 @@ static void ngx_resolver_expire(ngx_reso ngx_queue_t *queue); static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn); +static ngx_int_t ngx_resolver_send_udp_query(ngx_resolver_t *r, + ngx_resolver_connection_t *rec, u_char *query, u_short qlen); +static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r, + ngx_resolver_connection_t *rec, u_char *query, u_short qlen); static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn, ngx_str_t *name); static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r, @@ -72,12 +80,14 @@ static void ngx_resolver_resend_handler( static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue); static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r); -static void ngx_resolver_read_response(ngx_event_t *rev); +static void ngx_resolver_udp_read(ngx_event_t *rev); +static void ngx_resolver_tcp_write(ngx_event_t *wev); +static void ngx_resolver_tcp_read(ngx_event_t *rev); static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, - size_t n); + size_t n, ngx_uint_t tcp); 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 qtype, - ngx_uint_t nan, ngx_uint_t ans); + ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans); static 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, @@ -165,6 +175,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ r->ident = -1; r->resend_timeout = 5; + r->tcp_timeout = 5; r->expire = 30; r->valid = 0; @@ -241,6 +252,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ rec[j].sockaddr = u.addrs[j].sockaddr; rec[j].socklen = u.addrs[j].socklen; rec[j].server = u.addrs[j].name; + rec[j].resolver = r; } } @@ -279,6 +291,10 @@ ngx_resolver_cleanup(void *data) if (rec[i].udp) { ngx_close_connection(rec[i].udp); } + + if (rec[i].tcp) { + ngx_close_connection(rec[i].tcp); + } } ngx_free(r); @@ -691,8 +707,10 @@ ngx_resolve_name_locked(ngx_resolver_t * } rn->naddrs = (u_short) -1; + rn->tcp = 0; #if (NGX_HAVE_INET6) rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0; + rn->tcp6 = 0; #endif if (ngx_resolver_send_query(r, rn) != NGX_OK) { @@ -908,8 +926,10 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx } rn->naddrs = (u_short) -1; + rn->tcp = 0; #if (NGX_HAVE_INET6) rn->naddrs6 = (u_short) -1; + rn->tcp6 = 0; #endif if (ngx_resolver_send_query(r, rn) != NGX_OK) { @@ -1104,55 +1124,156 @@ ngx_resolver_expire(ngx_resolver_t *r, n static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn) { - ssize_t n; + ngx_int_t rc; ngx_resolver_connection_t *rec; rec = r->connections.elts; rec = &rec[rn->last_connection]; - if (rec->udp == NULL) { - + if (rec->log.handler == NULL) { rec->log = *r->log; rec->log.handler = ngx_resolver_log_error; rec->log.data = rec; rec->log.action = "resolving"; - + } + + if (rn->naddrs == (u_short) -1) { + rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen) + : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen); + + if (rc != NGX_OK) { + return rc; + } + } + +#if (NGX_HAVE_INET6) + + if (rn->query6 && rn->naddrs6 == (u_short) -1) { + rc = rn->tcp6 + ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen) + : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen); + + if (rc != NGX_OK) { + return rc; + } + } + +#endif + + return NGX_OK; +} + + +static ngx_int_t +ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, + u_char *query, u_short qlen) +{ + ssize_t n; + + if (rec->udp == NULL) { if (ngx_udp_connect(rec) != NGX_OK) { return NGX_ERROR; } - rec->udp->data = r; - rec->udp->read->handler = ngx_resolver_read_response; + rec->udp->data = rec; + rec->udp->read->handler = ngx_resolver_udp_read; rec->udp->read->resolver = 1; } - if (rn->naddrs == (u_short) -1) { - n = ngx_send(rec->udp, rn->query, rn->qlen); - - if (n == -1) { + n = ngx_send(rec->udp, query, qlen); + + if (n == -1) { + return NGX_ERROR; + } + + if ((size_t) n != (size_t) qlen) { + ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec, + u_char *query, u_short qlen) +{ + ngx_buf_t *b; + ngx_int_t rc; + + rc = NGX_OK; + + if (rec->tcp == NULL) { + b = rec->read_buf; + + if (b == NULL) { + b = ngx_resolver_calloc(r, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_ERROR; + } + + b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE); + if (b->start == NULL) { + return NGX_ERROR; + } + + b->end = b->start + NGX_RESOLVER_TCP_RSIZE; + + rec->read_buf = b; + } + + b->pos = b->start; + b->last = b->start; + + b = rec->write_buf; + + if (b == NULL) { + b = ngx_resolver_calloc(r, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_ERROR; + } + + b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE); + if (b->start == NULL) { + return NGX_ERROR; + } + + b->end = b->start + NGX_RESOLVER_TCP_WSIZE; + + rec->write_buf = b; + } + + b->pos = b->start; + b->last = b->start; + + rc = ngx_tcp_connect(rec); + if (rc == NGX_ERROR) { return NGX_ERROR; } - if ((size_t) n != (size_t) rn->qlen) { - ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); - return NGX_ERROR; - } + rec->tcp->data = rec; + rec->tcp->write->handler = ngx_resolver_tcp_write; + rec->tcp->read->handler = ngx_resolver_tcp_read; + rec->tcp->read->resolver = 1; + + ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000)); } -#if (NGX_HAVE_INET6) - if (rn->query6 && rn->naddrs6 == (u_short) -1) { - n = ngx_send(rec->udp, rn->query6, rn->qlen); - - if (n == -1) { - return NGX_ERROR; - } - - if ((size_t) n != (size_t) rn->qlen) { - ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete"); - return NGX_ERROR; - } + b = rec->write_buf; + + if (b->end - b->last < 2 + qlen) { + ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow"); + return NGX_ERROR; } -#endif + + *b->last++ = (u_char) (qlen >> 8); + *b->last++ = (u_char) qlen; + b->last = ngx_cpymem(b->last, query, qlen); + + if (rc == NGX_OK) { + ngx_resolver_tcp_write(rec->tcp->write); + } return NGX_OK; } @@ -1282,13 +1403,15 @@ ngx_resolver_resend_empty(ngx_resolver_t static void -ngx_resolver_read_response(ngx_event_t *rev) +ngx_resolver_udp_read(ngx_event_t *rev) { - ssize_t n; - ngx_connection_t *c; - u_char buf[NGX_RESOLVER_UDP_SIZE]; + ssize_t n; + ngx_connection_t *c; + ngx_resolver_connection_t *rec; + u_char buf[NGX_RESOLVER_UDP_SIZE]; c = rev->data; + rec = c->data; _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel