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