trafficserver的DNS初始化源码分析一

来源:互联网 发布:淘宝显示多少人付款 编辑:程序博客网 时间:2024/05/04 10:46
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://chenpiaoping.blog.51cto.com/5631143/1364486
SplitDNS

功能:SplitDNS可以配置ats使用多个DNS服务器,这样是处于安全考虑的。

配置:

1)开启splitdns,即proxy.config.dns.splitDNS.enabled的值设置为1

2)在splitdns.config里添加规则,这些规则可以实现那些请求使用哪个DNS服务器

records.configDNS相关的配置说明

proxy.config.dns.search_default_domains

当开启时,ats会在不合格的主机名后面添加本地域名,如,请求的主机名是host_x,而本地域名是y.com,当开启该配置项时,atshost_x扩展为host_x.y.com

proxy.config.dns.splitDNS.enabled

开启SplitDNS功能

proxy.config.dns.url_expansions

主机名的扩展后缀,当DNS解析失败时,会把主机名加上给扩展后缀后重试,如配置为org,则DNS查找失败后ats会在主机名后面加上.org后再重试DNS查找

proxy.config.dns.resolv_conf

DNS服务器的配置文件,这个文件的格式和resolv.conf一样,ats使用里面配置的DNS服务器。可以使用/etc/resolv.config或自己创建。

proxy.config.dns.nameservers
DNS服务器的配置,除了可以在proxy.config.dns.resolv_conf指定的文件里配置外,DNS服务器也可以在这里也可以配置,如果两个都配置了,优先使用这里配置的,如果都没有配置,在使用系统默认的/etc/resolv.conf
proxy.config.dns.dedicated_thread
是否要给DNS专门分配一个线程,默认为否
proxy.config.dns.validate_query_name
用于对付DNS伪造的,当发现DNS伪造时直接回弹
records.configHostDB相关配置说明
proxy.config.hostdb.serve_stale_for
当正在给过期的NS记录获取新的数据时,过期的NS记录能使用的时间(单位是秒),默认是0,即如果NS记录过期将不能再使用了
proxy.config.hostdb.storage_size
hostdb的总大小(单位是字节)
proxy.config.hostdb.size
hostdb中能存储的记录项的最大数,每条记录项至少为44字节,和hostdb的总大小息息相关
proxy.config.hostdb.ttl_mode
DNS记录超时的计算方法,0:以DNS响应里的超时时间为依据,1:以配置的超时时间(proxy.config.hostdb.timeout)为依据,2:选择两者之间较小的为依据,3:选择两者之间较大的为依据
proxy.config.hostdb.timeout
自定义的DNS记录的超时时间
proxy.config.hostdb.strict_round_robin
一次DNS响应可能一个域名解析到多个ip地址,默认相同http客户端会使用相同的源服务器,如果开启该配置项,则轮流使用解析到的多个ip地址
proxy.config.hostdb.ip_resolve
解析成ipv4还是ipv6,有四个值,可以配置多个,用分号隔开即可,顺序很重要,如果配置可个按顺序解析。client:根据客户端的地址族来解析,ipv4:解析成ipv4的地址,ipv6:解析成ipv6的地址,none:放弃解析

splitdns.config配置文件

配置该文件能实现的功能是,使得满足条件的http请求使用特定的DNS服务器来进行DNS查找,配置格式:

dest_domain=dest_domain | dest_host | url_regex named=dns_server def_domain=def_domain search_list=search_listdest_domain:目的域名,可以使用!表示“非”dest_host:目的主机,可以使用!表示“非”url_regex:url的正则表达式named:必选项,表示使用的DNS服务器,可以带端口,用冒号和ip地址隔开,没带端口默认使用53def_domain:可选项,默认的域名,search_list:可选项,用分号分割的域名列表DNS初始化DNS相关的初始化包括hostdbdnssplitdns的初始化main.cc

ink_hostdb_init(makeModuleVersion(HOSTDB_MODULE_MAJOR_VERSION,HOSTDB_MODULE_MINOR_VERSION ,PRIVATE_MODULE_HEADER));

ink_dns_init(makeModuleVersion(HOSTDB_MODULE_MAJOR_VERSION,HOSTDB_MODULE_MINOR_VERSION ,PRIVATE_MODULE_HEADER));

ink_split_dns_init(makeModuleVersion(1,0,PRIVATE_MODULE_HEADER));

//开启splitDNS的情况下进行读取splitdns.config的配置

#ifdefSPLIT_DNS

SplitDNSConfig::startup();

hostdb初始化:

main()--->ink_hostdb_init()

voidink_hostdb_init(ModuleVersionv)

{

......

ts_host_res_global_init();

}

省略部分为hostdb各种状态信息计数的初始化,直接调用ts_host_res_global_init()

main()--->ink_hostdb_init()--->ts_host_res_global_init()

voidts_host_res_global_init()

{

//Global configuration values.

memcpy(host_res_default_preference_order,

HOST_RES_DEFAULT_PREFERENCE_ORDER,

sizeof(host_res_default_preference_order));


char*ip_resolve = REC_ConfigReadString("proxy.config.hostdb.ip_resolve");

if(ip_resolve) {

parse_host_res_preferences(ip_resolve,host_res_default_preference_order);

}

ats_free(ip_resolve);

}

这个函数功能是读取配置项proxy.config.hostdb.ip_resolve(该配置项的意思参考前面的说明),然后调用函数parse_host_res_preferences进行解析,解析后把结果记录在全局的枚举数组 host_res_default_preference_order中

main()--->ink_hostdb_init()--->ts_host_res_global_init()--->parse_host_res_preferences()


voidparse_host_res_preferences(charconst*value,HostResPreferenceOrderorder) {

Tokenizertokens(";/|");

//preference from theconfigstring.

intnp = 0;// index in to @am_host_res_preference

boolfound[N_HOST_RES_PREFERENCE];  //redundancy check array

intn;// # of tokens

inti;// index

n= tokens.Initialize(value);

for( i = 0 ; i < N_HOST_RES_PREFERENCE ; ++i )

found[i] = false;

for( i = 0 ; i < n && np < N_HOST_RES_PREFERENCE_ORDER ;++i ) {

charconst*elt = tokens[i];

//special case none/only because that terminates the sequence.

if(0 ==strcasecmp(elt,HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_NONE])){

found[HOST_RES_PREFER_NONE]=true;

order[np] = HOST_RES_PREFER_NONE;

break;

}else{

//scan the other types

HostResPreference ep =HOST_RES_PREFER_NONE;

for(intip = HOST_RES_PREFER_NONE+ 1 ; ip < N_HOST_RES_PREFERENCE ; ++ip ) {

//如果是none,则后面的就不用看了

if(0 ==strcasecmp(elt,HOST_RES_PREFERENCE_STRING[ip])) {

ep =static_cast<HostResPreference>(ip);

break;

}

}

if(HOST_RES_PREFER_NONE!= ep && !found[ep]) {// ignoreduplicates

found[ep] = true;

order[np++] = ep;

}

}

}

if(!found[HOST_RES_PREFER_NONE]){

//If 'only' wasn't explicit, fill in the rest by default.

if(!found[HOST_RES_PREFER_IPV4])

order[np++] =HOST_RES_PREFER_IPV4;

if(!found[HOST_RES_PREFER_IPV6])

order[np++] =HOST_RES_PREFER_IPV6;

if(np < N_HOST_RES_PREFERENCE)

order[np++] =HOST_RES_PREFER_NONE;

}

}  

这个函数的功能是把配置项proxy.config.hostdb.ip_resolve的值按;/|分割,分割后逐个判断,然后把全局枚举数组中的元素设置成响应的枚举值,枚举结构如下:

enumHostResPreference {

HOST_RES_PREFER_NONE= 0,///< Invalid / initvalue.

HOST_RES_PREFER_CLIENT,///< Prefer family of clientconnection.

HOST_RES_PREFER_IPV4,///< Prefer IPv4.

HOST_RES_PREFER_IPV6///< Prefer IPv6

};

全局枚举数组的定义如下:

HostResPreferencehost_res_default_preference_order[N_HOST_RES_PREFERENCE_ORDER];

其中N_HOST_RES_PREFERENCE_ORDER3

dns初始化:

main()--->ink_dns_init()

void

ink_dns_init(ModuleVersionv)

{

......

}

这里都是dns各种状态信息计数的初始化,这些留到ats启动流程分析再介绍

dns初始化:

main()--->ink_split_dns_init()

void

ink_split_dns_init(ModuleVersionv)

{

staticintinit_called = 0;

ink_release_assert(!checkModuleVersion(v,SPLITDNS_MODULE_VERSION));

if(init_called)

return;

init_called = 1;

}

啥也没做,init_called1表示已经初始化

main()--->SplitDNSConfig::startup()

void

SplitDNSConfig::startup()

{

dnsHandler_mutex= new_ProxyMutex();

//startupjust check gsplit_dns_enabled

REC_ReadConfigInt32(gsplit_dns_enabled,"proxy.config.dns.splitDNS.enabled");

splitDNSUpdate = NEW(newConfigUpdateHandler<SplitDNSConfig>());

splitDNSUpdate->attach("proxy.config.cache.splitdns.filename");

}

创建并初始化互斥量dnsHandler_mutex

读取配置项proxy.config.dns.splitDNS.enabled,即splitDNS的开关,赋值给gsplit_dns_enabled

创建splitDNSUpdate,这里的核心就是调用splitDNSUpdate->attach注册回调函数ConfigUpdateHandler::update,一路跟踪这个函数最终调用的是SplitDNSConfigreconfigure()函数,也就是这里并没有立马读取文件splitdns.config的内容,只是创建好splitDNSUpdate,等到下面DNSProcessor::start()的时候才回调SplitDNSConfigreconfigure()来读取并解析splitdns.config文件。

下面该看dnshostdb的启动了,还是在main.cc中:

dnsProcessor.start(0,stacksize);

if(hostDBProcessor.start() < 0)

main()--->DNSProcessor::start()

int

DNSProcessor::start(int,size_tstacksize) {

//读取相应的配置项

REC_EstablishStaticConfigInt32(dns_retries,"proxy.config.dns.retries");

REC_EstablishStaticConfigInt32(dns_timeout,"proxy.config.dns.lookup_timeout");

REC_EstablishStaticConfigInt32(dns_search,"proxy.config.dns.search_default_domains");

REC_EstablishStaticConfigInt32(dns_failover_number,"proxy.config.dns.failover_number");

REC_EstablishStaticConfigInt32(dns_failover_period,"proxy.config.dns.failover_period");

REC_EstablishStaticConfigInt32(dns_max_dns_in_flight,"proxy.config.dns.max_dns_in_flight");

REC_EstablishStaticConfigInt32(dns_validate_qname,"proxy.config.dns.validate_query_name");

REC_EstablishStaticConfigInt32(dns_ns_rr,"proxy.config.dns.round_robin_nameservers");

REC_ReadConfigStringAlloc(dns_ns_list,"proxy.config.dns.nameservers");

REC_ReadConfigStringAlloc(dns_local_ipv4,"proxy.config.dns.local_ipv4");

REC_ReadConfigStringAlloc(dns_local_ipv6,"proxy.config.dns.local_ipv6");

REC_ReadConfigStringAlloc(dns_resolv_conf,"proxy.config.dns.resolv_conf");

REC_EstablishStaticConfigInt32(dns_thread,"proxy.config.dns.dedicated_thread");

//如果需要另启一个线程来处理DNS则创建一个线程

if(dns_thread > 0) {

ET_DNS =eventProcessor.spawn_event_threads(1,"ET_DNS",stacksize);

initialize_thread_for_net(eventProcessor.eventthread[ET_DNS][0]);

}else{//否则用线程池的即可

ET_DNS = ET_CALL;

}

thread= eventProcessor.eventthread[ET_DNS][0];

//dns失败时重试的时间间隔

dns_failover_try_period =dns_timeout + 1;

//如果开启splitDNS则读取并解析splitdns.config文件

if(SplitDNSConfig::gsplit_dns_enabled){

SplitDNSConfig::reconfigure();

}

dns_init();

open();

return0;

}

main()--->DNSProcessor::start()--->SplitDNSConfig::reconfigure()

void

SplitDNSConfig::reconfigure()

{

//如果没有开启splitDNS就没必要往下执行了

if(0 ==gsplit_dns_enabled)

return;

//创建splitDNS实例

SplitDNS*params = NEW(newSplitDNS);

//初始化splitDNS开关m_SplitDNSlEnable

params->m_SplitDNSlEnable=gsplit_dns_enabled;

//根据splitdns.config文件创建DNSserver

params->m_DNSSrvrTable= NEW(newDNS_table("proxy.config.dns.splitdns.filename",modulePrefix, &sdns_dest_tags));


//获取DNSserver表的大小

params->m_numEle= params->m_DNSSrvrTable->getEntryCount();

//如果DNSserver为空则设置splitDNS开关为关闭后退出

if(0 == params->m_DNSSrvrTable|| (0 == params->m_numEle)){

Warning("NoNAMEDs provided! Disabling SplitDNS");

gsplit_dns_enabled= 0;

deleteparams;

return;

}

//

if(0 != params->m_DNSSrvrTable->getHostMatcher()&&

0 ==params->m_DNSSrvrTable->getReMatcher()&&

0 ==params->m_DNSSrvrTable->getIPMatcher()&& 4 >= params->m_numEle){


HostLookup*pxHL = params->m_DNSSrvrTable->getHostMatcher()->getHLookup();

params->m_pxLeafArray= (void*) pxHL->getLArray();

params->m_bEnableFastPath=true;

}

//加到ats全局的配置信息结构infos中(留到ats启动流程来说)

m_id= configProcessor.set(m_id,params);

//如果debug开启,则打印splitDNS的配置信息

if(is_debug_tag_set("splitdns_config")){

SplitDNSConfig::print();

}

}

本文出自 “陈漂评的博客” 博客,请务必保留此出处http://chenpiaoping.blog.51cto.com/5631143/1364486

0 0