00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "libts.h"
00032
00033 #ifdef SPLIT_DNS
00034 #include <sys/types.h>
00035 #include "P_SplitDNS.h"
00036 #include "MatcherUtils.h"
00037 #include "HostLookup.h"
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047 static const char modulePrefix[] = "[SplitDNS]";
00048
00049 static ConfigUpdateHandler<SplitDNSConfig> * splitDNSUpdate;
00050
00051 static ClassAllocator<DNSRequestData> DNSReqAllocator("DNSRequestDataAllocator");
00052
00053
00054
00055
00056
00057 const matcher_tags sdns_dest_tags = {
00058 "dest_host", "dest_domain", NULL, "url_regex", "url", NULL, true
00059 };
00060
00061
00062
00063
00064
00065 enum SplitDNSCB_t
00066 {
00067 SDNS_FILE_CB,
00068 SDNS_ENABLE_CB
00069 };
00070
00071
00072 static const char *SDNSResultStr[] = {
00073 "DNSServer_Undefined",
00074 "DNSServer_Specified",
00075 "DNSServer_Failed"
00076 };
00077
00078
00079 int SplitDNSConfig::m_id = 0;
00080 int SplitDNSConfig::gsplit_dns_enabled = 0;
00081 int splitDNSFile_CB(const char *name, RecDataT data_type, RecData data, void *cookie);
00082 Ptr<ProxyMutex> SplitDNSConfig::dnsHandler_mutex;
00083
00084
00085
00086
00087
00088 inline SplitDNSResult::SplitDNSResult()
00089 : r(DNS_SRVR_UNDEFINED), m_line_number(0), m_rec(0), m_wrap_around(false)
00090 {
00091 }
00092
00093
00094
00095
00096
00097 SplitDNS::SplitDNS()
00098 : m_DNSSrvrTable(NULL), m_SplitDNSlEnable(0),
00099 m_bEnableFastPath(false), m_pxLeafArray(NULL), m_numEle(0)
00100 {
00101 }
00102
00103
00104 SplitDNS::~SplitDNS()
00105 {
00106 if (m_DNSSrvrTable) {
00107 delete m_DNSSrvrTable;
00108 }
00109 }
00110
00111
00112
00113
00114
00115 SplitDNS *
00116 SplitDNSConfig::acquire()
00117 {
00118 return (SplitDNS *) configProcessor.get(SplitDNSConfig::m_id);
00119 }
00120
00121
00122
00123
00124
00125 void
00126 SplitDNSConfig::release(SplitDNS * params)
00127 {
00128 configProcessor.release(SplitDNSConfig::m_id, params);
00129 }
00130
00131
00132
00133
00134
00135 void
00136 SplitDNSConfig::startup()
00137 {
00138 dnsHandler_mutex = new_ProxyMutex();
00139
00140
00141 REC_ReadConfigInt32(gsplit_dns_enabled, "proxy.config.dns.splitDNS.enabled");
00142 splitDNSUpdate = new ConfigUpdateHandler<SplitDNSConfig>();
00143 splitDNSUpdate->attach("proxy.config.cache.splitdns.filename");
00144 }
00145
00146
00147
00148
00149
00150 void
00151 SplitDNSConfig::reconfigure()
00152 {
00153 if (0 == gsplit_dns_enabled)
00154 return;
00155
00156 SplitDNS *params = new SplitDNS;
00157
00158 params->m_SplitDNSlEnable = gsplit_dns_enabled;
00159 params->m_DNSSrvrTable = new DNS_table("proxy.config.dns.splitdns.filename", modulePrefix, &sdns_dest_tags);
00160
00161 params->m_numEle = params->m_DNSSrvrTable->getEntryCount();
00162 if (0 == params->m_DNSSrvrTable || (0 == params->m_numEle)) {
00163 Warning("No NAMEDs provided! Disabling SplitDNS");
00164 gsplit_dns_enabled = 0;
00165 delete params;
00166 return;
00167 }
00168
00169 if (0 != params->m_DNSSrvrTable->getHostMatcher() &&
00170 0 == params->m_DNSSrvrTable->getReMatcher() &&
00171 0 == params->m_DNSSrvrTable->getIPMatcher() && 4 >= params->m_numEle) {
00172
00173 HostLookup *pxHL = params->m_DNSSrvrTable->getHostMatcher()->getHLookup();
00174 params->m_pxLeafArray = (void *) pxHL->getLArray();
00175 params->m_bEnableFastPath = true;
00176 }
00177
00178 m_id = configProcessor.set(m_id, params);
00179
00180 if (is_debug_tag_set("splitdns_config")) {
00181 SplitDNSConfig::print();
00182 }
00183 }
00184
00185
00186
00187
00188
00189 void
00190 SplitDNSConfig::print()
00191 {
00192 SplitDNS *params = SplitDNSConfig::acquire();
00193
00194 Debug("splitdns_config", "DNS Server Selection Config\n");
00195 Debug("splitdns_config", "\tEnabled=%d \n", params->m_SplitDNSlEnable);
00196
00197 params->m_DNSSrvrTable->Print();
00198 SplitDNSConfig::release(params);
00199 }
00200
00201
00202
00203
00204
00205 void *
00206 SplitDNS::getDNSRecord(const char *hostname)
00207 {
00208 Debug("splitdns", "Called SplitDNS::getDNSRecord(%s)", hostname);
00209
00210 DNSRequestData *pRD = DNSReqAllocator.alloc();
00211 pRD->m_pHost = hostname;
00212
00213 SplitDNSResult res;
00214 findServer(pRD, &res);
00215
00216 DNSReqAllocator.free(pRD);
00217
00218 if (DNS_SRVR_SPECIFIED == res.r) {
00219 return (void *) &(res.m_rec->m_servers);
00220 }
00221
00222 Debug("splitdns", "Fail to match a valid splitdns rule, fallback to default dns resolver");
00223 return NULL;
00224 }
00225
00226
00227
00228
00229
00230 void
00231 SplitDNS::findServer(RequestData * rdata, SplitDNSResult * result)
00232 {
00233 DNS_table *tablePtr = m_DNSSrvrTable;
00234 SplitDNSRecord *rec;
00235
00236 ink_assert(result->r == DNS_SRVR_UNDEFINED);
00237
00238 if (m_SplitDNSlEnable == 0) {
00239 result->r = DNS_SRVR_UNDEFINED;
00240 return;
00241 }
00242
00243 result->m_rec = NULL;
00244 result->m_line_number = 0xffffffff;
00245 result->m_wrap_around = false;
00246
00247
00248
00249
00250 if (m_bEnableFastPath) {
00251 SplitDNSRecord *data_ptr = 0;
00252 char *pHost = (char *) rdata->get_host();
00253 if (0 == pHost) {
00254 Warning("SplitDNS: No host to match !");
00255 return;
00256 }
00257
00258 int len = strlen(pHost);
00259 HostLeaf *pxHL = (HostLeaf *) m_pxLeafArray;
00260 for (int i = 0; i < m_numEle; i++) {
00261 if (0 == pxHL)
00262 break;
00263
00264 if (false == pxHL[i].isNot && pxHL[i].len > len)
00265 continue;
00266
00267 int idx = len - pxHL[i].len;
00268 char *pH = &pHost[idx];
00269 char *pMatch = (char *) pxHL[i].match;
00270 char cNot = *pMatch;
00271
00272 if ('!' == cNot)
00273 pMatch++;
00274
00275 int res = memcmp(pH, pMatch, pxHL[i].len);
00276
00277 if ((0 != res && '!' == cNot) || (0 == res && '!' != cNot)) {
00278 data_ptr = (SplitDNSRecord *) pxHL[i].opaque_data;
00279 data_ptr->UpdateMatch(result, rdata);
00280 break;
00281 }
00282 }
00283 } else {
00284 tablePtr->Match(rdata, result);
00285 }
00286
00287 rec = result->m_rec;
00288 if (rec == NULL) {
00289 result->r = DNS_SRVR_UNDEFINED;
00290 return;
00291 } else {
00292 result->r = DNS_SRVR_SPECIFIED;
00293 }
00294
00295 if (is_debug_tag_set("splitdns_config")) {
00296 const char *host = rdata->get_host();
00297
00298 switch (result->r) {
00299 case DNS_SRVR_FAIL:
00300 Debug("splitdns_config", "Result for %s was %s", host, SDNSResultStr[result->r]);
00301 break;
00302 case DNS_SRVR_SPECIFIED:
00303 Debug("splitdns_config", "Result for %s was dns servers \n", host);
00304 result->m_rec->Print();
00305 break;
00306 default:
00307
00308 break;
00309 }
00310 }
00311 }
00312
00313
00314
00315
00316
00317 const char *
00318 SplitDNSRecord::ProcessDNSHosts(char *val)
00319 {
00320 Tokenizer pTok(",; \t\r");
00321 int numTok;
00322 const char *current;
00323 int port = 0;
00324 char *tmp;
00325 int totsz = 0, sz = 0;
00326
00327 numTok = pTok.Initialize(val, SHARE_TOKS);
00328 if (MAXNS < numTok) {
00329 numTok = MAXNS;
00330 Warning("Only first %d DNS servers are tracked", numTok);
00331 }
00332 if (numTok == 0) {
00333 return "No servers specified";
00334 }
00335
00336
00337
00338
00339
00340 for (int i = 0; i < numTok; i++) {
00341 current = pTok[i];
00342 tmp = (char *) strchr(current, ':');
00343
00344 if (tmp != NULL && sscanf(tmp + 1, "%d", &port) != 1) {
00345 return "Malformed DNS port";
00346 }
00347
00348
00349
00350
00351
00352 if (tmp) {
00353 char *scan = tmp + 1;
00354 for (; *scan != '\0' && ParseRules::is_digit(*scan); scan++);
00355 for (; *scan != '\0' && ParseRules::is_wslfcr(*scan); scan++);
00356
00357 if (*scan != '\0') {
00358 return "Garbage trailing entry or invalid separator";
00359 }
00360
00361 if (tmp - current > (MAXDNAME - 1)) {
00362 return "DNS server name (ip) is too long";
00363 } else if (tmp - current == 0) {
00364 return "server string is emtpy";
00365 }
00366 *tmp = 0;
00367 }
00368
00369 if (0 != ats_ip_pton(current, &m_servers.x_server_ip[i].sa)) {
00370 return "invalid IP address given for a DNS server";
00371 }
00372
00373 ats_ip_port_cast(&m_servers.x_server_ip[i].sa) = htons(port ? port : NAMESERVER_PORT);
00374
00375 if ((MAXDNAME * 2 - 1) > totsz) {
00376 sz = strlen(current);
00377 memcpy((m_servers.x_dns_ip_line + totsz), current, sz);
00378 totsz += sz;
00379 }
00380 }
00381
00382 m_dnsSrvr_cnt = numTok;
00383 return NULL;
00384 }
00385
00386
00387
00388
00389
00390 const char *
00391 SplitDNSRecord::ProcessDefDomain(char *val)
00392 {
00393 Tokenizer pTok(",; \t\r");
00394 int numTok;
00395
00396 numTok = pTok.Initialize(val, SHARE_TOKS);
00397
00398 if (numTok > 1) {
00399 return "more than one default domain name specified";
00400 }
00401
00402 if (numTok == 0) {
00403 return "no default domain name specified";
00404 }
00405
00406 int len = 0;
00407 if (pTok[0] && 0 != (len = strlen(pTok[0]))) {
00408 memcpy(&m_servers.x_def_domain[0], pTok[0], len);
00409 m_servers.x_def_domain[len] = '\0';
00410 }
00411
00412 return NULL;
00413 }
00414
00415
00416
00417
00418
00419 const char *
00420 SplitDNSRecord::ProcessDomainSrchList(char *val)
00421 {
00422 Tokenizer pTok(",; \t\r");
00423 int numTok;
00424 int cnt = 0, sz = 0;
00425 char *pSp = 0;
00426 const char *current;
00427
00428 numTok = pTok.Initialize(val, SHARE_TOKS);
00429
00430 if (numTok == 0) {
00431 return "No servers specified";
00432 }
00433
00434 pSp = &m_servers.x_domain_srch_list[0];
00435
00436 for (int i = 0; i < numTok; i++) {
00437 current = pTok[i];
00438 cnt = sz += strlen(current);
00439
00440 if (MAXDNAME - 1 < sz)
00441 break;
00442
00443 memcpy(pSp, current, cnt);
00444 pSp += (cnt + 1);
00445 }
00446
00447 m_domain_srch_list = numTok;
00448 return NULL;
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458 char *
00459 SplitDNSRecord::Init(matcher_line * line_info)
00460 {
00461 const char *errPtr = NULL;
00462 const int errBufLen = 1024;
00463 char *errBuf = (char *)ats_malloc(errBufLen * sizeof(char));
00464 const char *tmp;
00465 char *label;
00466 char *val;
00467
00468 this->line_num = line_info->line_num;
00469 for (int i = 0; i < MATCHER_MAX_TOKENS; i++) {
00470 label = line_info->line[0][i];
00471 val = line_info->line[1][i];
00472
00473 if (label == NULL) {
00474 continue;
00475 }
00476
00477 if (strcasecmp(label, "def_domain") == 0) {
00478 if (NULL != (errPtr = ProcessDefDomain(val))) {
00479 snprintf(errBuf, errBufLen, "%s %s at line %d", modulePrefix, errPtr, line_num);
00480 return errBuf;
00481 }
00482 line_info->line[0][i] = NULL;
00483 line_info->num_el--;
00484 continue;
00485 }
00486
00487 if (strcasecmp(label, "search_list") == 0) {
00488 if (NULL != (errPtr = ProcessDomainSrchList(val))) {
00489 snprintf(errBuf, errBufLen, "%s %s at line %d", modulePrefix, errPtr, line_num);
00490 return errBuf;
00491 }
00492 line_info->line[0][i] = NULL;
00493 line_info->num_el--;
00494 continue;
00495 }
00496
00497 if (strcasecmp(label, "named") == 0) {
00498 if (NULL != (errPtr = ProcessDNSHosts(val))) {
00499 snprintf(errBuf, errBufLen, "%s %s at line %d", modulePrefix, errPtr, line_num);
00500 return errBuf;
00501 }
00502 line_info->line[0][i] = NULL;
00503 line_info->num_el--;
00504 continue;
00505 }
00506 }
00507
00508 if (!ats_is_ip(&m_servers.x_server_ip[0].sa)) {
00509 snprintf(errBuf, errBufLen, "%s No server specified in splitdns.config at line %d", modulePrefix, line_num);
00510 return errBuf;
00511 }
00512
00513 DNSHandler *dnsH = new DNSHandler;
00514 ink_res_state res = new ts_imp_res_state;
00515
00516 memset(res, 0, sizeof(ts_imp_res_state));
00517 if ((-1 == ink_res_init(res, m_servers.x_server_ip, m_dnsSrvr_cnt,
00518 m_servers.x_def_domain, m_servers.x_domain_srch_list, NULL))) {
00519 char ab[INET6_ADDRPORTSTRLEN];
00520 snprintf(errBuf, errBufLen,
00521 "Failed to build res record for the servers %s ...",
00522 ats_ip_ntop(&m_servers.x_server_ip[0].sa, ab, sizeof ab)
00523 );
00524 return errBuf;
00525 }
00526
00527 dnsH->m_res = res;
00528 dnsH->mutex = SplitDNSConfig::dnsHandler_mutex;
00529 dnsH->options = res->options;
00530 ats_ip_invalidate(&dnsH->ip.sa);
00531
00532 m_servers.x_dnsH = dnsH;
00533
00534 SET_CONTINUATION_HANDLER(dnsH, &DNSHandler::startEvent_sdns);
00535 (eventProcessor.eventthread[ET_DNS][0])->schedule_imm(dnsH);
00536
00537
00538
00539
00540 if (line_info->num_el > 0) {
00541 tmp = ProcessModifiers(line_info);
00542 if (tmp != NULL) {
00543 snprintf(errBuf, errBufLen, "%s %s at line %d in splitdns.config", modulePrefix, tmp, line_num);
00544 return errBuf;
00545 }
00546 }
00547
00548 if (errBuf)
00549 ats_free(errBuf);
00550
00551 return NULL;
00552 }
00553
00554
00555
00556
00557
00558 void
00559 SplitDNSRecord::UpdateMatch(SplitDNSResult * result, RequestData * )
00560 {
00561 int last_number = result->m_line_number;
00562
00563 if ((last_number<0) || (last_number> this->line_num)) {
00564 result->m_rec = this;
00565 result->m_line_number = this->line_num;
00566
00567 Debug("splitdns_config", "Matched with %p dns node from line %d", this, this->line_num);
00568 }
00569 }
00570
00571
00572
00573
00574
00575 void
00576 SplitDNSRecord::Print()
00577 {
00578 for (int i = 0; i < m_dnsSrvr_cnt; i++) {
00579 char ab[INET6_ADDRPORTSTRLEN];
00580 Debug("splitdns_config", " %s ", ats_ip_ntop(&m_servers.x_server_ip[i].sa, ab, sizeof ab));
00581 }
00582 }
00583
00584
00585 void
00586 ink_split_dns_init(ModuleVersion v)
00587 {
00588 static int init_called = 0;
00589
00590 ink_release_assert(!checkModuleVersion(v, SPLITDNS_MODULE_VERSION));
00591 if (init_called)
00592 return;
00593
00594 init_called = 1;
00595 }
00596
00597 #endif // SPLIT_DNS