查询完成后回调在ngx_resolver_ctx_t中指定的方法 真正的DNS查询完成后 , 不管成功 , 失败或是超时 , nginx会回调相应查询的handler, 如前面设置的:ngx_mail_smtp_resolve_name_handler 。在handler中都需要调用ngx_resolve_addr_done来标识查询结束 。static voidngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx){ in_addr_t addr; ngx_uint_t i; ngx_connection_t *c; struct sockaddr_in *sin; ngx_mail_session_t *s;s = ctx->data; c = s->connection;if (ctx->state) { ngx_log_error(NGX_LOG_ERR, c->log, 0, ""%V" could not be resolved (%i: %s)", &ctx->name, ctx->state, ngx_resolver_strerror(ctx->state)); } else { /* AF_INET only */ sin = (struct sockaddr_in *) c->sockaddr;for (i = 0; i < ctx->naddrs; i++) { addr = ctx->addrs[i];ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0, "name was resolved to %ud.%ud.%ud.%ud", (ntohl(addr) >> 24) & 0xff, (ntohl(addr) >> 16) & 0xff, (ntohl(addr) >> 8) & 0xff, ntohl(addr) & 0xff);if (addr == sin->sin_addr.s_addr) { goto found; } }s->host = smtp_unavailable; } found: //不管成功失败都要执行 ngx_resolve_name_done(ctx);}二、域名解析流程分析

文章插图
通过Nginx进行域名查询的流程图如下 , 颜色越深花费的时间越长 。调用过程分为三种:
- 首先判断是不是IPv4地址 , 如果是就直接调用Handler
- 再次检查是不是在缓存中 , 如果有 , 就调用Handler
- 最后发送远程DNS请求 , 收到回复后调用Handler
三、查询场景分析及实现介绍
查询的地址是IP v4地址
比如74.125.128.100, nginx会在ngx_resolve_start中通过ngx_inet_addr方法进行判断 , 如果是IPv4的地址 , 就设置好标志位 ngx_resolver_ctx_t->quick , 在接下来的ngx_resolve_name中会对这个标志位进行判断 , 如果为1 , 就直接调用ngx_resolver_ctx_t->handler
ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp){ in_addr_t addr; ngx_resolver_ctx_t *ctx;if (temp) { addr = ngx_inet_addr(temp->name.data, temp->name.len);if (addr != INADDR_NONE) { temp->resolver = r; temp->state = NGX_OK; temp->naddrs = 1; temp->addrs = &temp->addr; temp->addr = addr; temp->quick = 1;return temp; } } ...}
- 超时没有得到查询结果
- 调用ngx_resolve_name时设置的回调方法被调用 , 同时ngx_resolver_ctx_t->state被设置为NGX_RESOLVE_TIMEDOUT 。相应的代码为:
static voidngx_resolver_timeout_handler(ngx_event_t *ev){ ngx_resolver_ctx_t *ctx; ctx = ev->data; ctx->state = NGX_RESOLVE_TIMEDOUT; ctx->handler(ctx);}
- 正常查询一个不在缓存中的域名
- 如果要查询的域名不在缓存中 , 首先把域名按hash值放在缓存中 , 然后准备查询需要的数据 , 发送DNS查询的UDP请求给DNS服务器 ,
static ngx_int_tngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx){ ngx_resolver_node_t *rn; rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t)); ngx_rbtree_insert(&r->name_rbtree, &rn->node); ngx_resolver_create_name_query(rn, ctx); ngx_resolver_send_query(r, rn);rn->cnlen = 0; rn->naddrs = 0; rn->valid = 0; rn->waiting = ctx;ctx->state = NGX_AGAIN;} //收到DNS查询结果后的回调方法static voidngx_resolver_read_response(ngx_event_t *rev){ ssize_t n; ngx_connection_t *c; u_char buf[NGX_RESOLVER_UDP_SIZE]; c = rev->data;do { n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE); if (n < 0) { return; }ngx_resolver_process_response(c->data, buf, n); } while (rev->ready);} static voidngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last, ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans){ hash = ngx_crc32_short(name.data, name.len); rn = ngx_resolver_lookup_name(r, &name, hash);//copy addresses to cached node rn->u.addrs = addrs;//回调所有等待本域名解析的请求 next = rn->waiting; rn->waiting = NULL;while (next) { ctx = next; ctx->state = NGX_OK; ctx->naddrs = naddrs; ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; ctx->addr = addr; next = ctx->next;ctx->handler(ctx); }}
- 对同一域名查询多次查询
- 如果多次查询时 , 之前的查询结果还在缓存中并且没有失效 , 就直接从缓存中取到查询结果 , 并调用设置的回调方法 。
static ngx_int_tngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx){ uint32_t hash; in_addr_t addr, *addrs; ngx_uint_t naddrs; ngx_resolver_ctx_t *next; ngx_resolver_node_t *rn;hash = ngx_crc32_short(ctx->name.data, ctx->name.len); rn = ngx_resolver_lookup_name(r, &ctx->name, hash);if (rn) { if (rn->valid >= ngx_time()) { naddrs = rn->naddrs;if (naddrs) { ctx->next = rn->waiting; rn->waiting = NULL;do { ctx->state = NGX_OK; ctx->naddrs = naddrs; ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs; ctx->addr = addr; next = ctx->next;ctx->handler(ctx);ctx = next; } while (ctx);return NGX_OK; } } }}
推荐阅读
-
正商参阅@旺旺最强对手:三兄弟凑40万创业,打造百亿巨头企业,今年入超百亿
-
-
花盆屋顶长满佛甲草,薅几棵塞进花盆里,呼呼蔓延一阳台!
-
活人|秦陵兵马俑真是用活人烧制的吗?专家给出答复:打开看看就知道了
-
轿车|6万可买自动挡,2021款宝骏510正式上市 5.38万元起
-
产业气象站|| 火星号精选,不用担心量子计算机会对区块链产生威胁,它有可能被扼杀在摇篮中
-
#生肖#5月6号开始接好运,出门遇贵人,财运红发紫,富贵如意的生肖!
-
-
-
山寨币|2020-7-11秦川说币大饼底部企稳震荡是假象还是再次反转?
-
受到异性上司(年龄差距较大)骚扰,怎样拒绝比较体面又不得罪他(工作岗位其实不错,不想辞职)
-
-
iOS14|高通正式“背叛”美国?华为再次喜从天降?外媒:终究是躲不过了
-
微波炉怎么烤披萨步骤如下,微波炉如何烤披萨的做法-
-
-
大妈用80万普拉多装白菜,车主很无奈:我心疼,但不敢说
-
四川新闻网|【地评线】太阳鸟报评|全国消防日:“要要救”(119)!致敬身边的守护者——“火焰蓝”!
-
【江苏男篮】NBA再邀易建联,阿联选择让人泪目,网友:周琦你要吗?
-
[解放军这次西沙演练]解放军这次西沙演练 为何引起特别关注?
-
小米|小米集团:合计授出300万份购股权,行权价为每股13.6港元