Nginx的DNS解析過程分析

來源:互聯網
上載者:User

標籤:

Nginx怎麼做網域名稱解析?怎麼在你自己開發的模組裡面使用Nginx提供的方法解析網域名稱?它內部實現是什麼樣的?

本文以Nginx 1.5.1為例,從nginx_mail_smtp模組如何進行網域名稱解析出發,分析Nginx進行網域名稱解析的過程。為了簡化流程,突出重點,在範例程式碼中省掉了一些異常部分的處理,比如記憶體配置失敗等。DNS查詢分為兩種:根據網域名稱查詢地址和根據地址查詢網域名稱,在代碼結構上這兩種方式非常相似,這裡只介紹根據網域名稱查詢地址這一種方式。本文將從以下幾個方面進行介紹:

網域名稱查詢的函數介面介紹

網域名稱解析流程分析

查詢情境分析及實現介紹

一、網域名稱查詢的函數介面介紹

在使用同步IO的情況下,調用gethostbyname()或者gethostbyname_r()就可以根據網域名稱查詢到對應的IP地址, 但因為可能會通過網路進行遠程查詢,所以需要的時間比較長。

為了不阻塞當前線程,Nginx採用了非同步方式進行網域名稱查詢。整個查詢過程主要分為三個步驟,這點在各種非同步處理時都是一樣的:

準備函數調用需要的資訊,並設定回調方法

調用函數

處理結束後回調方法被調用

另外,為了盡量減少查詢花費的時間,Nginx還對查詢結果做了本機快取。為了初始化DNS Server地址和本機快取等資訊,需要在真正查詢前需要先進行一些全域的初始化操作。

下面先從調用者的角度對每個步驟做詳細的分析:

初始化網域名稱查詢所需要的的全域資訊

需要初始化的全域資訊包括:

DNS 伺服器的地址,如果指定了多個伺服器,nginx會採用Round Robin的方式輪流查詢每個伺服器

對查詢結果的緩衝,採用Red Black Tree的資料結構,以要查詢名字的Hash作為Key, 節點資訊存放在 struct ngx_resolver_node_t中。

因為resolver是全域的,與任何一個connection都無關,所有需要放在一個隨時都可以取到的地方,如 ngx_mail_core_srv_conf_t結構體上,在使用時從當前session找到ngx_mail_core_srv_conf_t,然後找到resolver。

DNS 伺服器的資訊需要在設定檔中明確指出,比如

1

2

3

4

5

6

#nginx.conf

 

resolver 8.8.8.8

#nginx 預設會根據DNS請求結果裡的TTL值來進行緩衝,

#當然也可以通過一個可選的參數valid來設定到期時間,如:

#resolver 127.0.0.1 [::1]:5353 valid=30s;

下面根據配置中的resolver參數,初始化全域的ngx_resolver_t,其中儲存了前面提及的DNS伺服器位址和查詢結果等資訊:

01

02

03

04

05

06

07

08

09

10

11

static char *

ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

    ngx_mail_core_srv_conf_t  *cscf = conf;

    ngx_str_t  *value;

    value = cf->args->elts;

 

    cscf->resolver = ngx_resolver_create(cf, &value[1], 

                                         cf->args->nelts - 1);

    return NGX_CONF_OK;

}

準備本次查詢的資訊

和本次查詢相關的資訊放在ngx_resolver_ctx_t結構體中,包括要查詢的名稱,查詢完的回調方法,以及逾時時間等。如果本次要查詢的地址已經是IPv4用點分隔的地址了,比如74.125.128.100, nginx會在ngx_resolve_start中進行判斷,並設定好標誌位,在調用ngx_resolve_name時不會發送真正的DNS查詢請求

static void

ngx_mail_smtp_resolve_name(ngx_event_t *rev)

{

    ngx_connection_t          *c;

    ngx_mail_session_t        *s;

    ngx_resolver_ctx_t        *ctx;

    ngx_mail_core_srv_conf_t  *cscf;

 

    c = rev->data;

    s = c->data;

 

    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);

 

    ctx = ngx_resolve_start(cscf->resolver, NULL);

    if (ctx == NULL) {

        ngx_mail_close_connection(c);

        return;

    }

 

    ctx->name = s->host;

    ctx->type = NGX_RESOLVE_A;

    ctx->handler = ngx_mail_smtp_resolve_name_handler;

    ctx->data = s;

    ctx->timeout = cscf->resolver_timeout;

 

    //根據名字進行IP地址查詢

    if (ngx_resolve_name(ctx) != NGX_OK) {

        ngx_mail_close_connection(c);


    }

}

根據名字進行IP地址查詢

前面方法的最後通過ngx_resolve_name方法進行IP地址查詢。查詢時,Nginx會先檢查本機快取,如果在緩衝中,就更新緩衝到期時間,並回調設定的handler, 如前面設定的:ngx_mail_smtp_resolve_name_handler,然後整個查詢過程結束。如果沒有在緩衝中就發送查詢請求給dns server,同時方法返回。

查詢完成後回調在ngx_resolver_ctx_t中指定的方法

真正的DNS查詢完成後,不管成功,失敗或是逾時,nginx會回調相應查詢的handler, 如前面設定的:ngx_mail_smtp_resolve_name_handler。在handler中都需要調用ngx_resolve_addr_done來標識查詢結束。

static void

ngx_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的DNS解析過程分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.