dns解析相關程式碼分析
轉載至:http://blog.chinaunix.net/uid-23242010-id-93354.html
TrafficServer提供了DNS解析相關的功能,相關模組為iocore/dns。目前dns模組還有很多問題需要解決[1]。
首先從配置管理上分析dns模組。以下給出ts配置檔案records.config中與dns相關的配置選項:
CONFIG proxy.config.dns.splitDNS.enabled INT 0 |
dns針對以上兩種解析方式,採用如下設計邏輯進行了實現:通過DNSProcessor+DNSHandler+DNSEntry實現dns解析;通過SplitDNS+SplitDNSConfig+SplitDNSRecord提供額外的splitdns解析功能。
(1)
dns解析遵循ts的非同步事件模型的設計原理[3],DNSProcessor藉助DNSHandler對一個域名進行解析。
DNSEntry類實現了對一個dns請求的封裝。ts內部實現封裝了一組與libresolv庫相同功能的方法[4],例如ink_res_int等等。
DNSHandler維護了兩個佇列:
struct DNSHandler: public Continuation |
if (dns_ns_rr) {//使用roundrobin |
根據以上分析,通過DNSHandler::startEvent,與dns解析伺服器進行連線。在startEvent函式中,通過下面兩行程式碼非同步週期呼叫DNSHandler::mainEvent:
SET_HANDLER(&DNSHandler::mainEvent);
dnsProcessor.thread->schedule_every(this, DNS_PERIOD); |
recv_dns(event, e); |
下面分析ts是如何將一個dns請求插入到DNSHandler維護的DNSEntry佇列中去的。前面提到,dns解析遵循ts的非同步事件模型的設計邏輯,這種設計邏輯通常由Processor排程Handler處理一個Continuation狀態序列,在這裡也不例外。DNSProcessor提供了一組get方法作域名解析,這些get方法都通過內部呼叫DNSProcessor::getby方法實現域名解析,以DNSProcessor::gethostbyname為例:
inline Action * |
DNSEntry *e = dnsEntryAllocator.alloc(); |
SET_HANDLER((DNSEntryHandler) & DNSEntry::mainEvent); |
dnsH->entries.enqueue(this); |
通過以上分析可以看出,dns解析通過DNSProcessor::getby不斷處理每一個dns請求,並構造dns訊息體插入到DNSHandler對應的DNSEntry佇列中去,DNSHandler定期呼叫DNSHandler::mainEvent方法從dns伺服器中取回dns響應,並根據其維護的DNSEntry佇列構造新的dns請求傳送給dns伺服器。
dns解析是通過DNSProcessor::start方法啟用的。該方法首先讀取一些配置選項,然後執行DNSProcessor::dns_init載入resolv_conf變數對應的檔案(預設為/etc/resolv.conf),最後執行DNSProcessor::open方法,該方法內部呼叫DNSHandler::startEvent,接下來按照上面描述的流程,一個dns解析服務就啟用了。
(2)
splitdns是後來的ts開發團隊在原有基礎上增加的功能,設計邏輯非常混亂,以TrafficServer2.1.4版本為例,整個程式碼巢狀在了iocore/dns,iocore/hostdb,以及proxy模組中。從功能上來看,目前splitdns的功能還不是很完善,後續需要很多改進,[1]介紹了後續的一些改進方案。以下大體介紹一下splitdns相關的一些關鍵程式碼。
1)SplitDNSConfig通過SplitDNSConfig::startup方法根據配置檔案選項選擇是否啟動splitdns功能,該函式呼叫SplitDNSConfig::reconfig函式。下面分析reconfig這個函式的內容:
IOCORE_ReadConfigInt32(gsplit_dns_enabled, "proxy.config.dns.splitDNS.enabled"); |
params->m_DNSSrvrTable = NEW(new DNS_table("proxy.config.dns.splitdns.filename", modulePrefix, &sdns_dest_tags)); |
typedef ControlMatcher<SplitDNSRecord, SplitDNSResult> DNS_table; |
函式體,裡面有這麼兩行關鍵程式碼:
Data *cur_d; |
2)通過SplitDNSConfig::startup方法,當在records.config檔案中enable splitdns後,splitdns已經開啟。我們接著分析SplitDNSRecord這個結構體,可以看出其內部有一個成員:
DNSServer m_servers; |
struct DNSServer |
3)SplitDNS這個結構體提供了對外的介面。SplitDNS::getDNSRecord解析引數指向的域名,並返回一個DNSServer,從而也間接得到了一個DNSHandler。將這個DNSHandler作為引數呼叫DNSProcessor::getby,就可以實現從splitdns模組解析一個域名了。
從上面的描述中我們可以看出,通過splitdns解析一個域名。只需要首先配置records.config檔案,將CONFIGproxy.config.dns.splitDNS.enabled賦值為1;然後通過
SplitDNSConfig::startup(); |
|