• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

SplitDNS.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /*****************************************************************************
00025  *
00026  *  SplitDNS.cc - Implementation of "split" DNS (as the name says)
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    this file is built using "ParentSelection.cc as a template.
00042    -------------    ------------------------------------------------- */
00043 
00044 /* --------------------------------------------------------------
00045    globals
00046    -------------------------------------------------------------- */
00047 static const char modulePrefix[] = "[SplitDNS]";
00048 
00049 static ConfigUpdateHandler<SplitDNSConfig> * splitDNSUpdate;
00050 
00051 static ClassAllocator<DNSRequestData> DNSReqAllocator("DNSRequestDataAllocator");
00052 
00053 /* --------------------------------------------------------------
00054    used by a lot of protocols. We do not have dest ip in most
00055    cases.
00056    -------------------------------------------------------------- */
00057 const matcher_tags sdns_dest_tags = {
00058   "dest_host", "dest_domain", NULL, "url_regex", "url", NULL, true
00059 };
00060 
00061 
00062 /* --------------------------------------------------------------
00063    config Callback Prototypes
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    SplitDNSResult::SplitDNSResult()
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    SplitDNS::SplitDNS()
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    SplitDNSConfig::acquire()
00114    -------------------------------------------------------------- */
00115 SplitDNS *
00116 SplitDNSConfig::acquire()
00117 {
00118   return (SplitDNS *) configProcessor.get(SplitDNSConfig::m_id);
00119 }
00120 
00121 
00122 /* --------------------------------------------------------------
00123    SplitDNSConfig::release()
00124    -------------------------------------------------------------- */
00125 void
00126 SplitDNSConfig::release(SplitDNS * params)
00127 {
00128   configProcessor.release(SplitDNSConfig::m_id, params);
00129 }
00130 
00131 
00132 /* --------------------------------------------------------------
00133    SplitDNSConfig::startup()
00134    -------------------------------------------------------------- */
00135 void
00136 SplitDNSConfig::startup()
00137 {
00138   dnsHandler_mutex = new_ProxyMutex();
00139 
00140   //startup just check gsplit_dns_enabled
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    SplitDNSConfig::reconfigure()
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    SplitDNSConfig::print()
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    SplitDNS::getDNSRecord()
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    SplitDNS::findServer()
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      the 'alleged' fast path ...
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       // DNS_SRVR_UNDEFINED
00308       break;
00309     }
00310   }
00311 }
00312 
00313 
00314 /* --------------------------------------------------------------
00315    SplitDNSRecord::ProcessDNSHosts()
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      Allocate the servers array and Loop through the
00338      set of servers specified
00339      ------------------------------------------------ */
00340   for (int i = 0; i < numTok; i++) {
00341     current = pTok[i];
00342     tmp = (char *) strchr(current, ':');
00343     // coverity[secure_coding]
00344     if (tmp != NULL && sscanf(tmp + 1, "%d", &port) != 1) {
00345       return "Malformed DNS port";
00346     }
00347 
00348     /* ----------------------------------------
00349        Make sure that is no garbage beyond the
00350        server port
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    SplitDNSRecord::ProcessDefDomain()
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    SplitDNSRecord::ProcessDomainSrchList()
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    SplitDNSRecord::Init()
00454 
00455    matcher_line* line_info - contains parsed label/value pairs
00456    of the current split.config line
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); // Mark to use default DNS.
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      Process any modifiers to the directive, if they exist
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     SplitDNSRecord::UpdateMatch()
00557    -------------------------------------------------------------- */
00558 void
00559 SplitDNSRecord::UpdateMatch(SplitDNSResult * result, RequestData * /* rdata ATS_UNUSED */)
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     SplitDNSRecord::Print()
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

Generated by  doxygen 1.7.1