您的位置:首页 > 其它

trafficserver的DNS初始化源码分析一

2017-05-06 17:41 477 查看
原文: http://chenpiaoping.blog.51cto.com/5631143/1364486

SplitDNS

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

配置:

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

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

records.config中DNS相关的配置说明

proxy.config.dns.search_default_domains

当开启时,ats会在不合格的主机名后面添加本地域名,如,请求的主机名是host_x,而本地域名是y.com,当开启该配置项时,ats把host_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.nameserversDNS服务器的配置,除了可以在proxy.config.dns.resolv_conf指定的文件里配置外,DNS服务器也可以在这里也可以配置,如果两个都配置了,优先使用这里配置的,如果都没有配置,在使用系统默认的/etc/resolv.confproxy.config.dns.dedicated_thread是否要给DNS专门分配一个线程,默认为否proxy.config.dns.validate_query_name用于对付DNS伪造的,当发现DNS伪造时直接回弹records.config中HostDB相关配置说明proxy.config.hostdb.serve_stale_for当正在给过期的NS记录获取新的数据时,过期的NS记录能使用的时间(单位是秒),默认是0,即如果NS记录过期将不能再使用了proxy.config.hostdb.storage_sizehostdb的总大小(单位是字节)proxy.config.hostdb.sizehostdb中能存储的记录项的最大数,每条记录项至少为44字节,和hostdb的总大小息息相关proxy.config.hostdb.ttl_modeDNS记录超时的计算方法,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相关的初始化包括hostdb、dns、splitdns的初始化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 the configstring.

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_ORDER为3

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_called置1表示已经初始化

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,一路跟踪这个函数最终调用的是SplitDNSConfig的reconfigure()函数,也就是这里并没有立马读取文件splitdns.config的内容,只是创建好splitDNSUpdate,等到下面DNSProcessor::start()的时候才回调SplitDNSConfig的reconfigure()来读取并解析splitdns.config文件。

下面该看dns和hostdb的启动了,还是在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();

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: