00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 #include "P_DNS.h" 
00025 #include <ts/ink_inet.h>
00026 
00027 #ifdef SPLIT_DNS
00028 #include "I_SplitDNS.h"
00029 #endif
00030 
00031 #define SRV_COST    (RRFIXEDSZ+0)
00032 #define SRV_WEIGHT  (RRFIXEDSZ+2)
00033 #define SRV_PORT    (RRFIXEDSZ+4)
00034 #define SRV_SERVER  (RRFIXEDSZ+6)
00035 #define SRV_FIXEDSZ (RRFIXEDSZ+6)
00036 
00037 EventType ET_DNS = ET_CALL;
00038 
00039 
00040 
00041 
00042 int dns_timeout = DEFAULT_DNS_TIMEOUT;
00043 int dns_retries = DEFAULT_DNS_RETRIES;
00044 int dns_search = DEFAULT_DNS_SEARCH;
00045 int dns_failover_number = DEFAULT_FAILOVER_NUMBER;
00046 int dns_failover_period = DEFAULT_FAILOVER_PERIOD;
00047 int dns_failover_try_period = DEFAULT_FAILOVER_TRY_PERIOD;
00048 int dns_max_dns_in_flight = MAX_DNS_IN_FLIGHT;
00049 int dns_validate_qname = 0;
00050 unsigned int dns_handler_initialized = 0;
00051 int dns_ns_rr = 0;
00052 int dns_ns_rr_init_down = 1;
00053 char *dns_ns_list = NULL;
00054 char *dns_resolv_conf = NULL;
00055 char *dns_local_ipv6 = NULL;
00056 char *dns_local_ipv4 = NULL;
00057 int dns_thread = 0;
00058 int dns_prefer_ipv6 = 0;
00059 namespace {
00060   
00061   inline char const* QtypeName(int qtype) {
00062     return T_AAAA == qtype ? "AAAA" : T_A == qtype ? "A" : "*";
00063   }
00064   inline bool is_addr_query(int qtype) {
00065     return qtype == T_A || qtype == T_AAAA;
00066   }
00067 }
00068 
00069 DNSProcessor dnsProcessor;
00070 ClassAllocator<DNSEntry> dnsEntryAllocator("dnsEntryAllocator");
00071 
00072 
00073 ClassAllocator<HostEnt> dnsBufAllocator("dnsBufAllocator", 2);
00074 
00075 
00076 
00077 
00078 
00079 static bool dns_process(DNSHandler *h, HostEnt *ent, int len);
00080 static DNSEntry *get_dns(DNSHandler *h, uint16_t id);
00081 
00082 static void dns_result(DNSHandler *h, DNSEntry *e, HostEnt *ent, bool retry);
00083 static void write_dns(DNSHandler *h);
00084 static bool write_dns_event(DNSHandler *h, DNSEntry *e);
00085 
00086 
00087 static int try_servers = 0;
00088 static int local_num_entries = 1;
00089 static int attempt_num_entries = 1;
00090 char try_server_names[DEFAULT_NUM_TRY_SERVER][MAXDNAME];
00091 
00092 static inline char *
00093 strnchr(char *s, char c, int len) {
00094   while (*s && *s != c && len)
00095     ++s, --len;
00096   return *s == c ? s : (char *) NULL;
00097 }
00098 
00099 static inline uint16_t
00100 ink_get16(const uint8_t *src) {
00101   uint16_t dst;
00102 
00103   NS_GET16(dst, src);
00104   return dst;
00105 }
00106 
00107 void HostEnt::free() {
00108   dnsBufAllocator.free(this);
00109 }
00110 
00111 void
00112 make_ipv4_ptr(in_addr_t addr, char *buffer)
00113 {
00114     char *p = buffer;
00115     uint8_t const* u = reinterpret_cast<uint8_t*>(&addr);
00116 
00117     if (u[3] > 99)
00118       *p++ = (u[3] / 100) + '0';
00119     if (u[3] > 9)
00120       *p++ = ((u[3] / 10) % 10) + '0';
00121     *p++ = u[3] % 10 + '0';
00122     *p++ = '.';
00123     if (u[2] > 99)
00124       *p++ = (u[2] / 100) + '0';
00125     if (u[2] > 9)
00126       *p++ = ((u[2] / 10) % 10) + '0';
00127     *p++ = u[2] % 10 + '0';
00128     *p++ = '.';
00129     if (u[1] > 99)
00130       *p++ = (u[1] / 100) + '0';
00131     if (u[1] > 9)
00132       *p++ = ((u[1] / 10) % 10) + '0';
00133     *p++ = u[1] % 10 + '0';
00134     *p++ = '.';
00135     if (u[0] > 99)
00136       *p++ = (u[0] / 100) + '0';
00137     if (u[0] > 9)
00138       *p++ = ((u[0] / 10) % 10) + '0';
00139     *p++ = u[0] % 10 + '0';
00140     *p++ = '.';
00141     ink_strlcpy(p, "in-addr.arpa", MAXDNAME - (p - buffer + 1));
00142 }
00143 
00144 void
00145 make_ipv6_ptr(in6_addr const* addr, char *buffer)
00146 {
00147     const char hex_digit[] = "0123456789abcdef";
00148     char *p = buffer;
00149     uint8_t const* src = addr->s6_addr;
00150     int i;
00151 
00152     for (i = TS_IP6_SIZE-1 ; i >= 0; --i) {
00153         *p++ = hex_digit[src[i] & 0x0f];
00154         *p++ = '.';
00155         *p++ = hex_digit[src[i] >> 4];
00156         *p++ = '.';
00157     }
00158 
00159     ink_strlcpy(p, "ip6.arpa", MAXDNAME - (p - buffer + 1));
00160 }
00161 
00162 
00163 
00164 
00165 
00166 int
00167 DNSProcessor::start(int, size_t stacksize) {
00168   
00169   
00170   
00171   REC_EstablishStaticConfigInt32(dns_retries, "proxy.config.dns.retries");
00172   REC_EstablishStaticConfigInt32(dns_timeout, "proxy.config.dns.lookup_timeout");
00173   REC_EstablishStaticConfigInt32(dns_search, "proxy.config.dns.search_default_domains");
00174   REC_EstablishStaticConfigInt32(dns_failover_number, "proxy.config.dns.failover_number");
00175   REC_EstablishStaticConfigInt32(dns_failover_period, "proxy.config.dns.failover_period");
00176   REC_EstablishStaticConfigInt32(dns_max_dns_in_flight, "proxy.config.dns.max_dns_in_flight");
00177   REC_EstablishStaticConfigInt32(dns_validate_qname, "proxy.config.dns.validate_query_name");
00178   REC_EstablishStaticConfigInt32(dns_ns_rr, "proxy.config.dns.round_robin_nameservers");
00179   REC_ReadConfigStringAlloc(dns_ns_list, "proxy.config.dns.nameservers");
00180   REC_ReadConfigStringAlloc(dns_local_ipv4, "proxy.config.dns.local_ipv4");
00181   REC_ReadConfigStringAlloc(dns_local_ipv6, "proxy.config.dns.local_ipv6");
00182   REC_ReadConfigStringAlloc(dns_resolv_conf, "proxy.config.dns.resolv_conf");
00183   REC_EstablishStaticConfigInt32(dns_thread, "proxy.config.dns.dedicated_thread");
00184 
00185   if (dns_thread > 0) {
00186     
00187     ET_DNS = eventProcessor.spawn_event_threads(1, "ET_DNS", stacksize);
00188     initialize_thread_for_net(eventProcessor.eventthread[ET_DNS][0]);
00189   } else {
00190     
00191     ET_DNS = ET_CALL;
00192   }
00193   thread = eventProcessor.eventthread[ET_DNS][0];
00194 
00195   dns_failover_try_period = dns_timeout + 1;    
00196 
00197   if (SplitDNSConfig::gsplit_dns_enabled) {
00198     
00199     SplitDNSConfig::reconfigure();
00200   }
00201 
00202   
00203   dns_init();
00204   open();
00205 
00206   return 0;
00207 }
00208 
00209 void
00210 DNSProcessor::open(sockaddr const* target, int aoptions)
00211 {
00212   DNSHandler *h = new DNSHandler;
00213 
00214   h->options = aoptions;
00215   h->mutex = thread->mutex;
00216   h->m_res = &l_res;
00217   ats_ip_copy(&h->local_ipv4.sa, &local_ipv4.sa);
00218   ats_ip_copy(&h->local_ipv6.sa, &local_ipv6.sa);
00219 
00220   if (target)
00221     ats_ip_copy(&h->ip, target);
00222   else
00223     ats_ip_invalidate(&h->ip); 
00224 
00225   if (!dns_handler_initialized)
00226     handler = h;
00227 
00228   SET_CONTINUATION_HANDLER(h, &DNSHandler::startEvent);
00229   thread->schedule_imm(h);
00230 }
00231 
00232 
00233 
00234 
00235 void
00236 DNSProcessor::dns_init()
00237 {
00238   gethostname(try_server_names[0], 255);
00239   Debug("dns", "localhost=%s\n", try_server_names[0]);
00240   Debug("dns", "Round-robin nameservers = %d\n", dns_ns_rr);
00241 
00242   IpEndpoint nameserver[MAX_NAMED];
00243   size_t nserv = 0;
00244 
00245   if (dns_ns_list) {
00246     Debug("dns", "Nameserver list specified \"%s\"\n", dns_ns_list);
00247     int i;
00248     char *last;
00249     char *ns_list = ats_strdup(dns_ns_list);
00250     char *ns = (char *) strtok_r(ns_list, " ,;\t\r", &last);
00251 
00252     for (i = 0, nserv = 0 ; (i < MAX_NAMED) && ns ; ++i) {
00253       Debug("dns", "Nameserver list - parsing \"%s\"\n", ns);
00254       bool err = false;
00255       int prt = DOMAIN_SERVICE_PORT;
00256       char* colon = 0; 
00257       
00258       if ('[' == *ns) {
00259         char* ndx = strchr(ns+1, ']');
00260         if (ndx) {
00261           if (':' == ndx[1]) colon = ndx+1;
00262         } else {
00263           err = true;
00264           Warning("Unmatched '[' in address for nameserver '%s', discarding.", ns);
00265         }
00266       } else colon = strchr(ns, ':');
00267 
00268       if (!err && colon) {
00269         *colon = '\0';
00270         
00271         if (sscanf(colon + 1, "%d%*s", &prt) != 1) {
00272           Debug("dns", "Unable to parse port number '%s' for nameserver '%s', discardin.", colon + 1, ns);
00273           Warning("Unable to parse port number '%s' for nameserver '%s', discarding.", colon + 1, ns);
00274           err = true;
00275         }
00276       }
00277 
00278       if (!err && 0 != ats_ip_pton(ns, &nameserver[nserv].sa)) {
00279         Debug("dns", "Invalid IP address given for nameserver '%s', discarding", ns);
00280         Warning("Invalid IP address given for nameserver '%s', discarding", ns);
00281         err = true;
00282       }
00283 
00284       if (!err) {
00285         ip_port_text_buffer buff;
00286 
00287         ats_ip_port_cast(&nameserver[nserv].sa) = htons(prt);
00288 
00289         Debug("dns", "Adding nameserver %s to nameserver list",
00290           ats_ip_nptop(&nameserver[nserv].sa, buff, sizeof(buff))
00291         );
00292         ++nserv;
00293       }
00294 
00295       ns = (char *) strtok_r(NULL, " ,;\t\r", &last);
00296     }
00297     ats_free(ns_list);
00298   }
00299   
00300   
00301   if (ink_res_init(&l_res, nameserver, nserv, NULL, NULL, dns_resolv_conf) < 0)
00302     Warning("Failed to build DNS res records for the servers (%s).  Using resolv.conf.", dns_ns_list);
00303 
00304   
00305 
00306   if (dns_local_ipv6) {
00307     if (0 != ats_ip_pton(dns_local_ipv6, &local_ipv6)) {
00308       ats_ip_invalidate(&local_ipv6);
00309       Warning("Invalid IP address '%s' for dns.local_ipv6 value, discarding.", dns_local_ipv6);
00310     } else if (!ats_is_ip6(&local_ipv6.sa)) {
00311       ats_ip_invalidate(&local_ipv6);
00312       Warning("IP address '%s' for dns.local_ipv6 value was not IPv6, discarding.", dns_local_ipv6);
00313     }
00314   }
00315 
00316   if (dns_local_ipv4) {
00317     if (0 != ats_ip_pton(dns_local_ipv4, &local_ipv4)) {
00318       ats_ip_invalidate(&local_ipv4);
00319       Warning("Invalid IP address '%s' for dns.local_ipv4 value, discarding.", dns_local_ipv4);
00320     } else if (!ats_is_ip4(&local_ipv4.sa)) {
00321       ats_ip_invalidate(&local_ipv4);
00322       Warning("IP address '%s' for dns.local_ipv4 value was not IPv4, discarding.", dns_local_ipv4);
00323     }
00324   }
00325 }
00326 
00327 
00328 
00329 
00330 
00331 
00332 
00333 
00334 
00335 inline int
00336 ink_dn_expand(const u_char *msg, const u_char *eom, const u_char *comp_dn, u_char *exp_dn, int length)
00337 {
00338   return::dn_expand((unsigned char *) msg, (unsigned char *) eom, (unsigned char *) comp_dn, (char *) exp_dn, length);
00339 }
00340 
00341 DNSProcessor::DNSProcessor()
00342   : thread(NULL), handler(NULL)
00343 {
00344   ink_zero(l_res);
00345   ink_zero(local_ipv6);
00346   ink_zero(local_ipv4);
00347 }
00348 
00349 void
00350 DNSEntry::init(const char *x, int len, int qtype_arg, Continuation* acont,
00351                DNSProcessor::Options const& opt)
00352 {
00353   qtype = qtype_arg;
00354   host_res_style = opt.host_res_style;
00355   if (is_addr_query(qtype)) {
00356       
00357       if (HOST_RES_IPV4 == host_res_style ||
00358           HOST_RES_IPV4_ONLY == host_res_style) {
00359           qtype = T_A;
00360       } else if (HOST_RES_IPV6 == host_res_style ||
00361                  HOST_RES_IPV6_ONLY == host_res_style) {
00362           qtype = T_AAAA;
00363       }
00364   }
00365   submit_time = ink_get_hrtime();
00366   action = acont;
00367   submit_thread = acont->mutex->thread_holding;
00368 
00369 #ifdef SPLIT_DNS
00370   if (SplitDNSConfig::gsplit_dns_enabled) {
00371     dnsH = opt.handler ? opt.handler : dnsProcessor.handler;
00372   } else {
00373     dnsH = dnsProcessor.handler;
00374   }
00375 #else
00376   dnsH = dnsProcessor.handler;
00377 #endif // SPLIT_DNS
00378 
00379   dnsH->txn_lookup_timeout = opt.timeout;
00380 
00381   mutex = dnsH->mutex;
00382 
00383   if (is_addr_query(qtype) || qtype == T_SRV) {
00384     if (len) {
00385       len = len > (MAXDNAME - 1) ? (MAXDNAME - 1) : len;
00386       memcpy(qname, x, len);
00387       qname[len] = 0;
00388       orig_qname_len = qname_len = len;
00389     } else {
00390       qname_len = ink_strlcpy(qname, x, MAXDNAME);
00391       orig_qname_len = qname_len;
00392     }
00393   } else {                    
00394     IpAddr const* ip = reinterpret_cast<IpAddr const*>(x);
00395     if (ip->isIp6())
00396       make_ipv6_ptr(&ip->_addr._ip6, qname);
00397     else if (ip->isIp4())
00398       make_ipv4_ptr(ip->_addr._ip4, qname);
00399     else
00400       ink_assert(!"T_PTR query to DNS must be IP address.");
00401   }
00402 
00403   SET_HANDLER((DNSEntryHandler) & DNSEntry::mainEvent);
00404 }
00405 
00406 
00407 
00408 
00409 
00410 
00411 void
00412 DNSHandler::open_con(sockaddr const* target, bool failed, int icon)
00413 {
00414   ip_port_text_buffer ip_text;
00415   PollDescriptor *pd = get_PollDescriptor(dnsProcessor.thread);
00416 
00417   if (!icon && target) {
00418     ats_ip_copy(&ip, target);
00419   } else if (!target) {
00420     target = &ip.sa;
00421   }
00422 
00423   Debug("dns", "open_con: opening connection %s", ats_ip_nptop(target, ip_text, sizeof ip_text));
00424 
00425   if (con[icon].fd != NO_FD) {  
00426     con[icon].eio.stop();
00427     con[icon].close();
00428   }
00429 
00430   if (con[icon].connect(
00431       target, DNSConnection::Options()
00432         .setNonBlockingConnect(true)
00433         .setNonBlockingIo(true)
00434         .setUseTcp(false)
00435         .setBindRandomPort(true)
00436         .setLocalIpv6(&local_ipv6.sa)
00437         .setLocalIpv4(&local_ipv4.sa)
00438     ) < 0) {
00439     Debug("dns", "opening connection %s FAILED for %d", ip_text, icon);
00440     if (!failed) {
00441       if (dns_ns_rr)
00442         rr_failure(icon);
00443       else
00444         failover();
00445     }
00446     return;
00447   } else {
00448     ns_down[icon] = 0;
00449     if (con[icon].eio.start(pd, &con[icon], EVENTIO_READ) < 0) {
00450       Error("[iocore_dns] open_con: Failed to add %d server to epoll list\n", icon);
00451     } else {
00452       con[icon].num = icon;
00453       Debug("dns", "opening connection %s SUCCEEDED for %d", ip_text, icon);
00454     }
00455   }
00456 }
00457 
00458 void
00459 DNSHandler::validate_ip() {
00460   if (!ip.isValid()) {
00461     
00462     
00463     if (!m_res->nscount || !ats_ip_copy(&ip.sa, &m_res->nsaddr_list[0].sa)) {
00464       Warning("bad nameserver config, fallback to loopback");
00465       ip.setToLoopback(AF_INET);
00466     }
00467   }
00468 }
00469 
00470 
00471 
00472 
00473 
00474 int
00475 DNSHandler::startEvent(int , Event *e)
00476 {
00477   
00478   
00479   Debug("dns", "DNSHandler::startEvent: on thread %d\n", e->ethread->id);
00480 
00481   this->validate_ip();
00482 
00483   if (!dns_handler_initialized) {
00484     
00485     
00486     
00487     
00488     dns_handler_initialized = 1;
00489     SET_HANDLER(&DNSHandler::mainEvent);
00490     if (dns_ns_rr) {
00491       int max_nscount = m_res->nscount;
00492       if (max_nscount > MAX_NAMED)
00493         max_nscount = MAX_NAMED;
00494       n_con = 0;
00495       for (int i = 0; i < max_nscount; i++) {
00496         ip_port_text_buffer buff;
00497         sockaddr *sa = &m_res->nsaddr_list[i].sa;
00498         if (ats_is_ip(sa)) {
00499           open_con(sa, false, n_con);
00500           ++n_con;
00501           Debug("dns_pas", "opened connection to %s, n_con = %d",
00502             ats_ip_nptop(sa, buff, sizeof(buff)),
00503             n_con
00504           );
00505         }
00506       }
00507       dns_ns_rr_init_down = 0;
00508     } else {
00509       open_con(0); 
00510       n_con = 1;
00511     }
00512     e->ethread->schedule_every(this, DNS_PERIOD);
00513 
00514     return EVENT_CONT;
00515   } else {
00516     ink_assert(false);          
00517     return EVENT_DONE;
00518   }
00519 }
00520 
00521 
00522 
00523 
00524 
00525 int
00526 DNSHandler::startEvent_sdns(int , Event *e)
00527 {
00528   Debug("dns", "DNSHandler::startEvent_sdns: on thread %d\n", e->ethread->id);
00529   this->validate_ip();
00530 
00531   SET_HANDLER(&DNSHandler::mainEvent);
00532   open_con(&ip.sa, false, n_con);
00533   ++n_con;                      
00534 
00535   e->schedule_every(DNS_PERIOD);
00536   return EVENT_CONT;
00537 }
00538 
00539 static inline int
00540 _ink_res_mkquery(ink_res_state res, char *qname, int qtype, char *buffer)
00541 {
00542   int r = ink_res_mkquery(res, QUERY, qname, C_IN, qtype,
00543                           NULL, 0, NULL, (unsigned char *) buffer,
00544                           MAX_DNS_PACKET_LEN);
00545   return r;
00546 }
00547 
00548 void
00549 DNSHandler::recover()
00550 {
00551   ip_text_buffer buff;
00552   Warning("connection to DNS server %s restored", ats_ip_ntop(&ip.sa, buff, sizeof(buff)));
00553   name_server = 0;
00554   switch_named(name_server);
00555 }
00556 
00557 void
00558 DNSHandler::retry_named(int ndx, ink_hrtime t, bool reopen)
00559 {
00560   if (reopen && ((t - last_primary_reopen) > DNS_PRIMARY_REOPEN_PERIOD)) {
00561     Debug("dns", "retry_named: reopening DNS connection for index %d", ndx);
00562     last_primary_reopen = t;
00563     con[ndx].close();
00564     open_con(&m_res->nsaddr_list[ndx].sa, true, ndx);
00565   }
00566 
00567   char buffer[MAX_DNS_PACKET_LEN];
00568   Debug("dns", "trying to resolve '%s' from DNS connection, ndx %d", try_server_names[try_servers], ndx);
00569   int r = _ink_res_mkquery(m_res, try_server_names[try_servers], T_A, buffer);
00570   try_servers = (try_servers + 1) % countof(try_server_names);
00571   ink_assert(r >= 0);
00572   if (r >= 0) {                 
00573     int res = socketManager.send(con[ndx].fd, buffer, r, 0);
00574     Debug("dns", "ping result = %d", res);
00575   }
00576 }
00577 
00578 void
00579 DNSHandler::try_primary_named(bool reopen)
00580 {
00581   ink_hrtime t = ink_get_hrtime();
00582   if (reopen && ((t - last_primary_reopen) > DNS_PRIMARY_REOPEN_PERIOD)) {
00583     Debug("dns", "try_primary_named: reopening primary DNS connection");
00584     last_primary_reopen = t;
00585     open_con(&ip.sa, true, 0);
00586   }
00587   if ((t - last_primary_retry) > DNS_PRIMARY_RETRY_PERIOD) {
00588     char buffer[MAX_DNS_PACKET_LEN];
00589 
00590     last_primary_retry = t;
00591     Debug("dns", "trying to resolve '%s' from primary DNS connection", try_server_names[try_servers]);
00592     int r = _ink_res_mkquery(m_res, try_server_names[try_servers], T_A, buffer);
00593     
00594     
00595     if (local_num_entries < DEFAULT_NUM_TRY_SERVER)
00596       try_servers = (try_servers + 1) % local_num_entries;
00597     else
00598       try_servers = (try_servers + 1) % countof(try_server_names);
00599     ink_assert(r >= 0);
00600     if (r >= 0) {               
00601       int res = socketManager.send(con[0].fd, buffer, r, 0);
00602       Debug("dns", "ping result = %d", res);
00603     }
00604   }
00605 }
00606 
00607 
00608 void
00609 DNSHandler::switch_named(int ndx)
00610 {
00611   for (DNSEntry *e = entries.head; e; e = (DNSEntry *) e->link.next) {
00612     e->written_flag = 0;
00613     if (e->retries < dns_retries)
00614       ++(e->retries);           
00615   }
00616   in_flight = 0;
00617   received_one(ndx);            
00618 }
00619 
00620 
00621 void
00622 DNSHandler::failover()
00623 {
00624   Debug("dns", "failover: initiating failover attempt, current name_server=%d", name_server);
00625   
00626   if (m_res->nscount > 1) {
00627     ip_text_buffer buff1, buff2;
00628     int max_nscount = m_res->nscount;
00629 
00630     if (max_nscount > MAX_NAMED)
00631       max_nscount = MAX_NAMED;
00632     sockaddr const* old_addr = &m_res->nsaddr_list[name_server].sa;
00633     name_server = (name_server + 1) % max_nscount;
00634     Debug("dns", "failover: failing over to name_server=%d", name_server);
00635 
00636     IpEndpoint target;
00637     ats_ip_copy(&target.sa, &m_res->nsaddr_list[name_server].sa);
00638 
00639     Warning("failover: connection to DNS server %s lost, move to %s",
00640       ats_ip_ntop(old_addr, buff1, sizeof(buff1)),
00641       ats_ip_ntop(&target.sa, buff2, sizeof(buff2))
00642     );
00643 
00644     if (!target.isValid()) target.setToLoopback(AF_INET);
00645 
00646     open_con(&target.sa, true, name_server);
00647     if (n_con <= name_server)
00648       n_con = name_server + 1;
00649     switch_named(name_server);
00650   } else {
00651     ip_text_buffer buff;
00652     Warning("failover: connection to DNS server %s lost, retrying",
00653       ats_ip_ntop(&ip.sa, buff, sizeof(buff))
00654     );
00655   }
00656 }
00657 
00658 
00659 void
00660 DNSHandler::rr_failure(int ndx)
00661 {
00662   
00663   if (!ns_down[ndx]) {
00664     ip_text_buffer buff;
00665     
00666     Debug("dns", "rr_failure: Marking nameserver %d as down", ndx);
00667     ns_down[ndx] = 1;
00668     Warning("connection to DNS server %s lost, marking as down",
00669       ats_ip_ntop(&m_res->nsaddr_list[ndx].sa, buff, sizeof(buff))
00670     );
00671   }
00672 
00673   int nscount = m_res->nscount;
00674   if (nscount > MAX_NAMED)
00675     nscount = MAX_NAMED;
00676 
00677   
00678   int all_down = 1;
00679 
00680   for (int i = 0; i < nscount && all_down; i++) {
00681     Debug("dns", "nsdown[%d]=%d", i, ns_down[i]);
00682     if (!ns_down[i]) {
00683       all_down = 0;
00684     }
00685   }
00686 
00687   if (all_down && !dns_ns_rr_init_down) {
00688     Warning("connection to all DNS servers lost, retrying");
00689     
00690     
00691     for (DNSEntry *e = entries.head; e; e = (DNSEntry *) e->link.next) {
00692       e->written_flag = 0;
00693       if (e->retries < dns_retries)
00694         ++(e->retries);         
00695       --in_flight;
00696       DNS_DECREMENT_DYN_STAT(dns_in_flight_stat);
00697     }
00698   } else {
00699     
00700     for (DNSEntry *e = entries.head; e; e = (DNSEntry *) e->link.next) {
00701       if (e->which_ns == ndx) {
00702         e->written_flag = 0;
00703         if (e->retries < dns_retries)
00704           ++(e->retries);       
00705         --in_flight;
00706         DNS_DECREMENT_DYN_STAT(dns_in_flight_stat);
00707       }
00708     }
00709   }
00710 }
00711 
00712 static inline unsigned int get_rcode(char* buff) {
00713   return reinterpret_cast<HEADER*>(buff)->rcode;
00714 }
00715 
00716 static inline unsigned int get_rcode(HostEnt* ent) {
00717   return get_rcode(reinterpret_cast<char*>(ent));
00718 }
00719 
00720 static bool
00721 good_rcode(char *buff) {
00722   unsigned int r = get_rcode(buff);
00723   return NOERROR == r || NXDOMAIN == r;
00724 }
00725 
00726 
00727 void
00728 DNSHandler::recv_dns(int , Event * )
00729 {
00730   DNSConnection *dnsc = NULL;
00731   ip_text_buffer ipbuff1, ipbuff2;
00732 
00733   while ((dnsc = (DNSConnection *) triggered.dequeue())) {
00734     while (1) {
00735       IpEndpoint from_ip;
00736       socklen_t from_length = sizeof(from_ip);
00737 
00738       if (!hostent_cache)
00739         hostent_cache = dnsBufAllocator.alloc();
00740       HostEnt *buf = hostent_cache;
00741 
00742       int res = socketManager.recvfrom(dnsc->fd, buf->buf, MAX_DNS_PACKET_LEN, 0, &from_ip.sa, &from_length);
00743 
00744       if (res == -EAGAIN)
00745         break;
00746       if (res <= 0) {
00747         Debug("dns", "named error: %d", res);
00748         if (dns_ns_rr)
00749           rr_failure(dnsc->num);
00750         else if (dnsc->num == name_server)
00751           failover();
00752         break;
00753       }
00754 
00755       
00756       if (!ats_ip_addr_eq(&dnsc->ip.sa, &from_ip.sa)) {
00757         Warning("unexpected DNS response from %s (expected %s)",
00758           ats_ip_ntop(&from_ip.sa, ipbuff1, sizeof ipbuff1),
00759           ats_ip_ntop(&dnsc->ip.sa, ipbuff2, sizeof ipbuff2)
00760         );
00761         continue;
00762       }
00763       hostent_cache = 0;
00764       buf->packet_size = res;
00765       Debug("dns", "received packet size = %d", res);
00766       if (dns_ns_rr) {
00767         Debug("dns", "round-robin: nameserver %d DNS response code = %d", dnsc->num, get_rcode(buf));
00768         if (good_rcode(buf->buf)) {
00769           received_one(dnsc->num);
00770           if (ns_down[dnsc->num]) {
00771             Warning("connection to DNS server %s restored",
00772               ats_ip_ntop(&m_res->nsaddr_list[dnsc->num].sa, ipbuff1, sizeof ipbuff1)
00773             );
00774             ns_down[dnsc->num] = 0;
00775           }
00776         }
00777       } else {
00778         if (!dnsc->num) {
00779           Debug("dns", "primary DNS response code = %d", get_rcode(buf));
00780           if (good_rcode(buf->buf)) {
00781             if (name_server)
00782               recover();
00783             else
00784               received_one(name_server);
00785           }
00786         }
00787       }
00788       Ptr<HostEnt> protect_hostent = make_ptr(buf);
00789       if (dns_process(this, buf, res)) {
00790         if (dnsc->num == name_server)
00791           received_one(name_server);
00792       }
00793     }
00794   }
00795 }
00796 
00797 
00798 int
00799 DNSHandler::mainEvent(int event, Event *e)
00800 {
00801   recv_dns(event, e);
00802   if (dns_ns_rr) {
00803     ink_hrtime t = ink_get_hrtime();
00804     if (t - last_primary_retry > DNS_PRIMARY_RETRY_PERIOD) {
00805       for (int i = 0; i < n_con; i++) {
00806         if (ns_down[i]) {
00807           Debug("dns", "mainEvent: nameserver = %d is down", i);
00808           retry_named(i, t, true);
00809         }
00810       }
00811       last_primary_retry = t;
00812     }
00813     for (int i = 0; i < n_con; i++) {
00814       if (!ns_down[i] && failover_soon(i)) {
00815         Debug("dns", "mainEvent: nameserver = %d failover soon", name_server);
00816         if (failover_now(i))
00817           rr_failure(i);
00818         else {
00819           Debug("dns", "mainEvent: nameserver = %d no failover now - retrying", i);
00820           retry_named(i, t, false);
00821           ++failover_soon_number[i];
00822         }
00823       }
00824     }
00825   } else {
00826     if (failover_soon(name_server)) {
00827       Debug("dns", "mainEvent: will failover soon");
00828       if (failover_now(name_server)) {
00829         Debug("dns", "mainEvent: failing over now to another nameserver");
00830         failover();
00831       } else {
00832         try_primary_named(false);
00833         ++failover_soon_number[name_server];
00834       }
00835     } else if (name_server)     
00836       try_primary_named(true);
00837   }
00838 
00839   if (entries.head)
00840     write_dns(this);
00841 
00842   return EVENT_CONT;
00843 }
00844 
00845 
00846 inline static DNSEntry *
00847 get_dns(DNSHandler *h, uint16_t id)
00848 {
00849   for (DNSEntry *e = h->entries.head; e; e = (DNSEntry *) e->link.next) {
00850     if (e->once_written_flag) {
00851       for (int j = 0; j < MAX_DNS_RETRIES; j++) {
00852         if (e->id[j] == id) {
00853           return e;
00854         } else if (e->id[j] < 0) {
00855           goto Lnext;
00856         }
00857       }
00858     }
00859   Lnext:;
00860   }
00861   return NULL;
00862 }
00863 
00864 
00865 inline static DNSEntry *
00866 get_entry(DNSHandler *h, char *qname, int qtype)
00867 {
00868   for (DNSEntry *e = h->entries.head; e; e = (DNSEntry *) e->link.next) {
00869     if (e->qtype == qtype) {
00870       if (is_addr_query(qtype)) {
00871         if (!strcmp(qname, e->qname))
00872           return e;
00873       } else if (0 == memcmp(qname, e->qname, e->qname_len))
00874         return e;
00875     }
00876   }
00877   return NULL;
00878 }
00879 
00880 
00881 static void
00882 write_dns(DNSHandler *h)
00883 {
00884   ProxyMutex *mutex = h->mutex;
00885   DNS_INCREMENT_DYN_STAT(dns_total_lookups_stat);
00886   int max_nscount = h->m_res->nscount;
00887   if (max_nscount > MAX_NAMED)
00888     max_nscount = MAX_NAMED;
00889 
00890   if (h->in_write_dns)
00891     return;
00892   h->in_write_dns = true;
00893   
00894   if (h->in_flight < dns_max_dns_in_flight) {
00895     DNSEntry *e = h->entries.head;
00896     while (e) {
00897       DNSEntry *n = (DNSEntry *) e->link.next;
00898       if (!e->written_flag) {
00899         if (dns_ns_rr) {
00900           int ns_start = h->name_server;
00901           do {
00902             h->name_server = (h->name_server + 1) % max_nscount;
00903           } while (h->ns_down[h->name_server] && h->name_server != ns_start);
00904         }
00905         if (!write_dns_event(h, e))
00906           break;
00907       }
00908       if (h->in_flight >= dns_max_dns_in_flight)
00909         break;
00910       e = n;
00911     }
00912   }
00913   h->in_write_dns = false;
00914 }
00915 
00916 uint16_t
00917 DNSHandler::get_query_id()
00918 {
00919   uint16_t q1, q2;
00920   q2 = q1 = (uint16_t)(generator.random() & 0xFFFF);
00921   if (query_id_in_use(q2)) {
00922     uint16_t i = q2>>6;
00923     while (qid_in_flight[i] == UINT64_MAX) {
00924       if (++i ==  sizeof(qid_in_flight)/sizeof(uint64_t)) {
00925         i = 0;
00926       }
00927       if (i == q1>>6) {
00928         Error("[iocore_dns] get_query_id: Exhausted all DNS query ids");
00929         return q1;
00930       }
00931     }
00932     i <<= 6;
00933     q2 &= 0x3F;
00934     while (query_id_in_use(i+q2)) {
00935       ++q2;
00936       q2 &= 0x3F;
00937       if (q2 == (q1 & 0x3F)) {
00938         Error("[iocore_dns] get_query_id: Exhausted all DNS query ids");
00939         return q1;
00940       }
00941     }
00942     q2 += i;
00943   }
00944 
00945   set_query_id_in_use(q2);
00946   return q2;
00947 }
00948 
00949 
00950 
00951 
00952 
00953 
00954 
00955 static bool
00956 write_dns_event(DNSHandler *h, DNSEntry *e)
00957 {
00958   ProxyMutex *mutex = h->mutex;
00959   union {
00960     HEADER _h;
00961     char _b[MAX_DNS_PACKET_LEN];
00962   } blob;
00963   int r = 0;
00964 
00965   if ((r = _ink_res_mkquery(h->m_res, e->qname, e->qtype, blob._b)) <= 0) {
00966     Debug("dns", "cannot build query: %s", e->qname);
00967     dns_result(h, e, NULL, false);
00968     return true;
00969   }
00970 
00971   uint16_t i = h->get_query_id();
00972   blob._h.id = htons(i);
00973   if (e->id[dns_retries - e->retries] >= 0) {
00974     
00975     h->release_query_id(e->id[dns_retries - e->retries]);
00976   }
00977   e->id[dns_retries - e->retries] = i;
00978   Debug("dns", "send query (qtype=%d) for %s to fd %d", e->qtype, e->qname, h->con[h->name_server].fd);
00979 
00980   int s = socketManager.send(h->con[h->name_server].fd, blob._b, r, 0);
00981   if (s != r) {
00982     Debug("dns", "send() failed: qname = %s, %d != %d, nameserver= %d", e->qname, s, r, h->name_server);
00983     
00984     if (s < 0) {
00985       if (dns_ns_rr)
00986         h->rr_failure(h->name_server);
00987       else
00988         h->failover();
00989     }
00990     return false;
00991   }
00992 
00993   e->written_flag = true;
00994   e->which_ns = h->name_server;
00995   e->once_written_flag = true;
00996   ++h->in_flight;
00997   DNS_INCREMENT_DYN_STAT(dns_in_flight_stat);
00998 
00999   e->send_time = ink_get_hrtime();
01000 
01001   if (e->timeout)
01002     e->timeout->cancel();
01003 
01004   if (h->txn_lookup_timeout) {
01005     e->timeout = h->mutex->thread_holding->schedule_in(e, HRTIME_MSECONDS(h->txn_lookup_timeout));      
01006   } else {
01007     e->timeout = h->mutex->thread_holding->schedule_in(e, HRTIME_SECONDS(dns_timeout));
01008   }
01009 
01010   Debug("dns", "sent qname = %s, id = %u, nameserver = %d", e->qname, e->id[dns_retries - e->retries], h->name_server);
01011   h->sent_one();
01012   return true;
01013 }
01014 
01015 
01016 int
01017 DNSEntry::delayEvent(int event, Event *e)
01018 {
01019   (void) event;
01020   if (dnsProcessor.handler) {
01021     SET_HANDLER((DNSEntryHandler) & DNSEntry::mainEvent);
01022     return handleEvent(EVENT_IMMEDIATE, e);
01023   }
01024   e->schedule_in(DNS_DELAY_PERIOD);
01025   return EVENT_CONT;
01026 }
01027 
01028 
01029 int
01030 DNSEntry::mainEvent(int event, Event *e)
01031 {
01032   switch (event) {
01033   default:
01034     ink_assert(!"bad case");
01035     return EVENT_DONE;
01036   case EVENT_IMMEDIATE:{
01037       if (!dnsH)
01038         dnsH = dnsProcessor.handler;
01039       if (!dnsH) {
01040         Debug("dns", "handler not found, retrying...");
01041         SET_HANDLER((DNSEntryHandler) & DNSEntry::delayEvent);
01042         return handleEvent(event, e);
01043       }
01044 
01045       
01046       if (dns_search && ('.' != qname[orig_qname_len - 1])) {
01047         domains = dnsH->m_res->dnsrch;
01048         
01049         
01050         if (domains && !strnchr(qname, '.', MAXDNAME)) {
01051           qname[orig_qname_len] = '.';
01052           qname_len = orig_qname_len + 1 + ink_strlcpy(qname + orig_qname_len + 1, *domains,
01053                                                        MAXDNAME - (orig_qname_len + 1));
01054           ++domains;
01055         }
01056       } else {
01057         domains = NULL;
01058       }
01059       Debug("dns", "enqueing query %s", qname);
01060       DNSEntry *dup = get_entry(dnsH, qname, qtype);
01061       if (dup) {
01062         Debug("dns", "collapsing NS request");
01063         dup->dups.enqueue(this);
01064       } else {
01065         Debug("dns", "adding first to collapsing queue");
01066         dnsH->entries.enqueue(this);
01067         write_dns(dnsH);
01068       }
01069       return EVENT_DONE;
01070     }
01071   case EVENT_INTERVAL:
01072     Debug("dns", "timeout for query %s", qname);
01073     if (dnsH->txn_lookup_timeout) {
01074       timeout = NULL;
01075       dns_result(dnsH, this, result_ent, false);        
01076       return EVENT_DONE;
01077     }
01078     if (written_flag) {
01079       Debug("dns", "marking %s as not-written", qname);
01080       written_flag = false;
01081       --(dnsH->in_flight);
01082       DNS_DECREMENT_DYN_STAT(dns_in_flight_stat);
01083     }
01084     timeout = NULL;
01085     dns_result(dnsH, this, result_ent, true);
01086     return EVENT_DONE;
01087   }
01088 }
01089 
01090 Action *
01091 DNSProcessor::getby(const char *x, int len, int type, Continuation *cont, Options const& opt)
01092 {
01093   Debug("dns", "received query %s type = %d, timeout = %d", x, type, opt.timeout);
01094   if (type == T_SRV) {
01095     Debug("dns_srv", "DNSProcessor::getby attempting an SRV lookup for %s, timeout = %d", x, opt.timeout);
01096   }
01097   DNSEntry *e = dnsEntryAllocator.alloc();
01098   e->retries = dns_retries;
01099   e->init(x, len, type, cont, opt);
01100   MUTEX_TRY_LOCK(lock, e->mutex, this_ethread());
01101   if (!lock)
01102     thread->schedule_imm(e);
01103   else
01104     e->handleEvent(EVENT_IMMEDIATE, 0);
01105   return &e->action;
01106 }
01107 
01108 
01109 
01110 
01111 
01112 static void
01113 dns_result(DNSHandler *h, DNSEntry *e, HostEnt *ent, bool retry) {
01114   ProxyMutex *mutex = h->mutex;
01115   bool cancelled = (e->action.cancelled ? true : false);
01116 
01117   if (!ent && !cancelled) {
01118     
01119     if (retry && e->retries) {
01120       Debug("dns", "doing retry for %s", e->qname);
01121 
01122       DNS_INCREMENT_DYN_STAT(dns_retries_stat);
01123 
01124       --(e->retries);
01125       write_dns(h);
01126       return;
01127     } else if (e->domains && *e->domains) {
01128       do {
01129         Debug("dns", "domain extending, last tried '%s', original '%.*s'", e->qname, e->orig_qname_len, e->qname);
01130 
01131         
01132         if (e->orig_qname_len + strlen(*e->domains) + 2 > MAXDNAME) {
01133           Debug("dns", "domain too large %.*s + %s", e->orig_qname_len, e->qname, *e->domains);
01134         } else {
01135           e->qname[e->orig_qname_len] = '.';
01136           e->qname_len = e->orig_qname_len + 1 + ink_strlcpy(e->qname + e->orig_qname_len + 1, *e->domains,
01137                                                              MAXDNAME - (e->orig_qname_len + 1));
01138           ++(e->domains);
01139           e->retries = dns_retries;
01140           Debug("dns", "new name = %s retries = %d", e->qname, e->retries);
01141           write_dns(h);
01142 
01143           return;
01144         }
01145 
01146         
01147         ++(e->domains);
01148       } while (*e->domains);
01149     } else {
01150       e->qname[e->qname_len] = 0;
01151       if (!strchr(e->qname, '.') && !e->last) {
01152         e->last = true;
01153         write_dns(h);
01154         return;
01155       }
01156     }
01157     if (retry) {
01158       DNS_INCREMENT_DYN_STAT(dns_max_retries_exceeded_stat);
01159     }
01160   }
01161   if (ent == BAD_DNS_RESULT)
01162     ent = NULL;
01163   if (!cancelled) {
01164     if (!ent) {
01165       DNS_SUM_DYN_STAT(dns_fail_time_stat, ink_get_hrtime() - e->submit_time);
01166     } else {
01167       DNS_SUM_DYN_STAT(dns_success_time_stat, ink_get_hrtime() - e->submit_time);
01168     }
01169   }
01170   h->entries.remove(e);
01171 
01172   if (is_debug_tag_set("dns")) {
01173     if (is_addr_query(e->qtype)) {
01174       ip_text_buffer buff;
01175       char const* ptr = "<none>";
01176       char const* result = "FAIL";
01177       if (ent) {
01178         result = "SUCCESS";
01179         ptr = inet_ntop(e->qtype == T_AAAA ? AF_INET6 : AF_INET, ent->ent.h_addr_list[0], buff, sizeof(buff));
01180       }
01181       Debug("dns", "%s result for %s = %s retry %d", result, e->qname, ptr, retry);
01182     } else {
01183       if (ent) {
01184         Debug("dns", "SUCCESS result for %s = %s af=%d retry %d", e->qname, ent->ent.h_name, ent->ent.h_addrtype, retry);
01185       } else {
01186         Debug("dns", "FAIL result for %s = <not found> retry %d", e->qname, retry);
01187       }
01188     }
01189   }
01190 
01191   if (ent) {
01192     DNS_INCREMENT_DYN_STAT(dns_lookup_success_stat);
01193   } else {
01194     DNS_INCREMENT_DYN_STAT(dns_lookup_fail_stat);
01195   }
01196 
01197   DNSEntry *dup = NULL;
01198   while ((dup = e->dups.dequeue())) {
01199     if (dup->post(h, ent)) {
01200       e->dups.enqueue(dup);
01201       goto Lretry;
01202     }
01203   }
01204 
01205   if (e->timeout) {
01206     e->timeout->cancel(e);
01207     e->timeout = NULL;
01208   }
01209   e->result_ent = ent;
01210 
01211   if (h->mutex->thread_holding == e->submit_thread) {
01212     MUTEX_TRY_LOCK(lock, e->action.mutex, h->mutex->thread_holding);
01213     if (!lock) {
01214       Debug("dns", "failed lock for result %s", e->qname);
01215       goto Lretry;
01216     }
01217     for (int i = 0; i < MAX_DNS_RETRIES; i++) {
01218       if (e->id[i] < 0)
01219         break;
01220       h->release_query_id(e->id[i]);
01221     }
01222     e->postEvent(0, 0);
01223   } else {
01224     for (int i = 0; i < MAX_DNS_RETRIES; i++) {
01225       if (e->id[i] < 0)
01226         break;
01227       h->release_query_id(e->id[i]);
01228     }
01229     e->mutex = e->action.mutex;
01230     SET_CONTINUATION_HANDLER(e, &DNSEntry::postEvent);
01231     e->submit_thread->schedule_imm_signal(e);
01232   }
01233   return;
01234 Lretry:
01235   e->result_ent = ent;
01236   e->retries = 0;
01237   if (e->timeout)
01238     e->timeout->cancel();
01239   e->timeout = h->mutex->thread_holding->schedule_in(e, DNS_PERIOD);
01240 }
01241 
01242 int
01243 DNSEntry::post(DNSHandler *h, HostEnt *ent)
01244 {
01245   if (timeout) {
01246     timeout->cancel(this);
01247     timeout = NULL;
01248   }
01249   result_ent = ent;
01250   if (h->mutex->thread_holding == submit_thread) {
01251     MUTEX_TRY_LOCK(lock, action.mutex, h->mutex->thread_holding);
01252     if (!lock) {
01253       Debug("dns", "failed lock for result %s", qname);
01254       return 1;
01255     }
01256     postEvent(0, 0);
01257   } else {
01258     mutex = action.mutex;
01259     SET_HANDLER(&DNSEntry::postEvent);
01260     submit_thread->schedule_imm_signal(this);
01261   }
01262   return 0;
01263 }
01264 
01265 int
01266 DNSEntry::postEvent(int , Event * )
01267 {
01268   if (!action.cancelled) {
01269     Debug("dns", "called back continuation for %s", qname);
01270     action.continuation->handleEvent(DNS_EVENT_LOOKUP, result_ent);
01271   }
01272   result_ent = NULL;
01273   action.mutex = NULL;
01274   mutex = NULL;
01275   dnsEntryAllocator.free(this);
01276   return EVENT_DONE;
01277 }
01278 
01279 
01280 static bool
01281 dns_process(DNSHandler *handler, HostEnt *buf, int len)
01282 {
01283   ProxyMutex *mutex = handler->mutex;
01284   HEADER *h = (HEADER *) (buf->buf);
01285   DNSEntry *e = get_dns(handler, (uint16_t) ntohs(h->id));
01286   bool retry = false;
01287   bool server_ok = true;
01288   uint32_t temp_ttl = 0;
01289 
01290   
01291   
01292   
01293   if (!e || !e->written_flag) {
01294     Debug("dns", "unknown DNS id = %u", (uint16_t) ntohs(h->id));
01295     return false;               
01296   }
01297   
01298   
01299   
01300   e->written_flag = false;
01301   --(handler->in_flight);
01302   DNS_DECREMENT_DYN_STAT(dns_in_flight_stat);
01303 
01304   DNS_SUM_DYN_STAT(dns_response_time_stat, ink_get_hrtime() - e->send_time);
01305 
01306   if (h->rcode != NOERROR || !h->ancount) {
01307     Debug("dns", "received rcode = %d", h->rcode);
01308     switch (h->rcode) {
01309     default:
01310       Warning("Unknown DNS error %d for [%s]", h->rcode, e->qname);
01311       retry = true;
01312       server_ok = false;        
01313       goto Lerror;
01314     case SERVFAIL:             
01315       retry = true;
01316     case FORMERR:              
01317     case REFUSED:
01318     case NOTIMP:
01319       Debug("dns", "DNS error %d for [%s]", h->rcode, e->qname);
01320       server_ok = false;        
01321       goto Lerror;
01322     case NOERROR:
01323     case NXDOMAIN:
01324     case 6:                    
01325     case 7:                    
01326     case 8:                    
01327     case 9:                    
01328     case 10:                   
01329       Debug("dns", "DNS error %d for [%s]", h->rcode, e->qname);
01330       goto Lerror;
01331     }
01332   } else {
01333 
01334     
01335     
01336     
01337     
01338     u_char tbuf[MAXDNAME + 1];
01339     buf->ent.h_name = NULL;
01340 
01341     int ancount = ntohs(h->ancount);
01342     unsigned char *bp = buf->hostbuf;
01343     int buflen = sizeof(buf->hostbuf);
01344     u_char *cp = ((u_char *) h) + HFIXEDSZ;
01345     u_char *eom = (u_char *) h + len;
01346     int n;
01347     ink_assert(buf->srv_hosts.srv_host_count == 0 && buf->srv_hosts.srv_hosts_length == 0);
01348     buf->srv_hosts.srv_host_count = 0;
01349     buf->srv_hosts.srv_hosts_length = 0;
01350     unsigned& num_srv = buf->srv_hosts.srv_host_count;
01351     int rname_len = -1;
01352 
01353     
01354     
01355     
01356     if ((n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen)) < 0)
01357       goto Lerror;
01358 
01359     
01360     if (dns_validate_qname) {
01361       int qlen = e->qname_len;
01362       int rlen = strlen((char *)bp);
01363 
01364       rname_len = rlen; 
01365       if ((qlen > 0) && ('.' == e->qname[qlen-1]))
01366         --qlen;
01367       if ((rlen > 0) && ('.' == bp[rlen-1]))
01368         --rlen;
01369       
01370       
01371       
01372       if ((qlen != rlen) || (strncasecmp(e->qname, (const char*)bp, qlen) != 0)) {
01373         
01374         Warning("received DNS response with query name of '%s', but response query name is '%s'", e->qname, bp);
01375         goto Lerror;
01376       } else {
01377         Debug("dns", "query name validated properly for %s", e->qname);
01378       }
01379     }
01380 
01381     cp += n + QFIXEDSZ;
01382     if (is_addr_query(e->qtype)) {
01383       if (-1 == rname_len)
01384         n = strlen((char *)bp) + 1;
01385       else
01386         n = rname_len + 1;
01387       buf->ent.h_name = (char *) bp;
01388       bp += n;
01389       buflen -= n;
01390     }
01391     
01392     
01393     
01394     u_char **ap = buf->host_aliases;
01395     buf->ent.h_aliases = (char **) buf->host_aliases;
01396     u_char **hap = (u_char **) buf->h_addr_ptrs;
01397     *hap = NULL;
01398     buf->ent.h_addr_list = (char **) buf->h_addr_ptrs;
01399 
01400     
01401     
01402     
01403     
01404     
01405     
01406 
01407     
01408     
01409     if (local_num_entries >= DEFAULT_NUM_TRY_SERVER) {
01410       if ((attempt_num_entries % 50) == 0) {
01411         try_servers = (try_servers + 1) % countof(try_server_names);
01412         ink_strlcpy(try_server_names[try_servers], e->qname, MAXDNAME);
01413         memset(&try_server_names[try_servers][strlen(e->qname)], 0, 1);
01414         attempt_num_entries = 0;
01415       }
01416       ++attempt_num_entries;
01417     } else {
01418       
01419       try_servers = local_num_entries++;
01420       ink_strlcpy(try_server_names[try_servers], e->qname, MAXDNAME);
01421       memset(&try_server_names[try_servers][strlen(e->qname)], 0, 1);
01422     }
01423 
01424     
01425 
01426 
01427     unsigned char *here = (unsigned char *) buf->buf + HFIXEDSZ;
01428     if (e->qtype == T_SRV) {
01429       for (int ctr = ntohs(h->qdcount); ctr > 0; ctr--) {
01430         int strlen = dn_skipname(here, eom);
01431         here += strlen + QFIXEDSZ;
01432       }
01433     }
01434     
01435     
01436     
01437     int answer = false, error = false;
01438 
01439     while (ancount-- > 0 && cp < eom && !error) {
01440       n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen);
01441       if (n < 0) {
01442         ++error;
01443         break;
01444       }
01445       cp += n;
01446       short int type;
01447       NS_GET16(type, cp);
01448       cp += NS_INT16SZ;  
01449       NS_GET32(temp_ttl, cp); 
01450       if ((temp_ttl < buf->ttl) || (buf->ttl == 0))
01451         buf->ttl = temp_ttl;
01452       NS_GET16(n, cp);
01453 
01454       
01455       
01456       
01457       if (is_addr_query(e->qtype) && type == T_CNAME) {
01458         if (ap >= &buf->host_aliases[DNS_MAX_ALIASES - 1])
01459           continue;
01460         n = ink_dn_expand((u_char *) h, eom, cp, tbuf, sizeof(tbuf));
01461         if (n < 0) {
01462           ++error;
01463           break;
01464         }
01465         cp += n;
01466         *ap++ = (unsigned char *) bp;
01467         n = strlen((char *) bp) + 1;
01468         bp += n;
01469         buflen -= n;
01470         n = strlen((char *) tbuf) + 1;
01471         if (n > buflen) {
01472           ++error;
01473           break;
01474         }
01475         ink_strlcpy((char *) bp, (char *) tbuf, buflen);
01476         bp += n;
01477         buflen -= n;
01478         Debug("dns", "received cname = %s", tbuf);
01479         continue;
01480       }
01481       if (e->qtype != type) {
01482         ++error;
01483         break;
01484       }
01485       
01486       
01487       
01488       if (type == T_PTR) {
01489         n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen);
01490         if (n < 0) {
01491           ++error;
01492           break;
01493         }
01494         cp += n;
01495         if (!answer) {
01496           buf->ent.h_name = (char *) bp;
01497           Debug("dns", "received PTR name = %s", bp);
01498           n = strlen((char *) bp) + 1;
01499           bp += n;
01500           buflen -= n;
01501         } else if (ap < &buf->host_aliases[DNS_MAX_ALIASES - 1]) {
01502           *ap++ = bp;
01503           Debug("dns", "received PTR alias = %s", bp);
01504           n = strlen((char *) bp) + 1;
01505           bp += n;
01506           buflen -= n;
01507         }
01508       } else if (type == T_SRV) {
01509         if (num_srv >= HOST_DB_MAX_ROUND_ROBIN_INFO)
01510           break;
01511         cp = here;              
01512         int strlen = dn_skipname(cp, eom);
01513         cp += strlen;
01514         const unsigned char *srv_off = cp;
01515         cp += SRV_FIXEDSZ;
01516         cp += dn_skipname(cp, eom);
01517         here = cp;              
01518         SRV *srv = &buf->srv_hosts.hosts[num_srv];
01519         int r = ink_ns_name_ntop(srv_off + SRV_SERVER, srv->host, MAXDNAME);
01520         if (r <= 0) {
01521           
01522           ++error;
01523           goto Lerror;
01524         }
01525         Debug("dns_srv", "Discovered SRV record [from NS lookup] with cost:%d weight:%d port:%d with host:%s",
01526             ink_get16(srv_off + SRV_COST),
01527             ink_get16(srv_off + SRV_WEIGHT), ink_get16(srv_off + SRV_PORT), srv->host);
01528 
01529         srv->port = ink_get16(srv_off + SRV_PORT);
01530         srv->priority = ink_get16(srv_off + SRV_COST);
01531         srv->weight = ink_get16(srv_off + SRV_WEIGHT);
01532         srv->host_len = r;
01533         srv->host[r-1] = '\0';
01534         srv->key = makeHostHash(srv->host);
01535 
01536         if (srv->host[0] != '\0')
01537           buf->srv_hosts.srv_hosts_length += r;
01538         else
01539           continue;
01540         ++num_srv;
01541       } else if (is_addr_query(type)) {
01542         if (answer) {
01543           if (n != buf->ent.h_length) {
01544             cp += n;
01545             continue;
01546           }
01547         } else {
01548           int nn;
01549           buf->ent.h_length = n;
01550           buf->ent.h_addrtype = T_A == type ? AF_INET : AF_INET6;
01551           buf->ent.h_name = (char *) bp;
01552           nn = strlen((char *) bp) + 1;
01553           Debug("dns", "received %s name = %s", QtypeName(type), bp);
01554           bp += nn;
01555           buflen -= nn;
01556         }
01557         
01558         if (!(((uintptr_t) cp) % sizeof(unsigned int))) {
01559           *hap++ = cp;
01560           cp += n;
01561         } else {
01562           ip_text_buffer ip_string;
01563           bp = (unsigned char *) align_pointer_forward(bp, sizeof(int));
01564           if (bp + n >= buf->hostbuf + DNS_HOSTBUF_SIZE) {
01565             ++error;
01566             break;
01567           }
01568           memcpy((*hap++ = bp), cp, n);
01569           Debug("dns", "received %s = %s", QtypeName(type),
01570             inet_ntop(T_AAAA == type ? AF_INET6 : AF_INET, bp, ip_string, sizeof(ip_string))
01571           );
01572           bp += n;
01573           cp += n;
01574         }
01575       } else
01576         goto Lerror;
01577       ++answer;
01578     }
01579     if (answer) {
01580       *ap = NULL;
01581       *hap = NULL;
01582       
01583       
01584       
01585       
01586       if (!buf->ent.h_name) {
01587         Debug("dns", "inserting name = %s", e->qname);
01588         ink_strlcpy((char *) bp, e->qname, sizeof(buf->hostbuf) - (bp - buf->hostbuf));
01589         buf->ent.h_name = (char *) bp;
01590       }
01591       dns_result(handler, e, buf, retry);
01592       return server_ok;
01593     }
01594   }
01595 Lerror:;
01596   DNS_INCREMENT_DYN_STAT(dns_lookup_fail_stat);
01597   dns_result(handler, e, NULL, retry);
01598   return server_ok;
01599 }
01600 
01601 
01602 RecRawStatBlock *dns_rsb;
01603 
01604 void
01605 ink_dns_init(ModuleVersion v)
01606 {
01607   static int init_called = 0;
01608 
01609   Debug("dns", "ink_dns_init: called with init_called = %d", init_called);
01610 
01611   ink_release_assert(!checkModuleVersion(v, HOSTDB_MODULE_VERSION));
01612   if (init_called)
01613     return;
01614 
01615   init_called = 1;
01616   
01617   
01618   dns_rsb = RecAllocateRawStatBlock((int) DNS_Stat_Count);
01619 
01620   
01621   
01622   
01623   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01624                      "proxy.process.dns.total_dns_lookups",
01625                      RECD_INT, RECP_PERSISTENT, (int) dns_total_lookups_stat, RecRawStatSyncSum);
01626 
01627   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01628                      "proxy.process.dns.lookup_avg_time",
01629                      RECD_INT, RECP_PERSISTENT, (int) dns_response_time_stat, RecRawStatSyncHrTimeAvg);
01630 
01631   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01632                      "proxy.process.dns.success_avg_time",
01633                      RECD_INT, RECP_NON_PERSISTENT, (int) dns_success_time_stat, RecRawStatSyncHrTimeAvg);
01634 
01635   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01636                      "proxy.process.dns.lookup_successes",
01637                      RECD_INT, RECP_PERSISTENT, (int) dns_lookup_success_stat, RecRawStatSyncSum);
01638 
01639   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01640                      "proxy.process.dns.fail_avg_time",
01641                      RECD_INT, RECP_PERSISTENT, (int) dns_fail_time_stat, RecRawStatSyncHrTimeAvg);
01642 
01643   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01644                      "proxy.process.dns.lookup_failures",
01645                      RECD_INT, RECP_PERSISTENT, (int) dns_lookup_fail_stat, RecRawStatSyncSum);
01646 
01647   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01648                      "proxy.process.dns.retries", RECD_INT, RECP_PERSISTENT, (int) dns_retries_stat, RecRawStatSyncSum);
01649 
01650   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01651                      "proxy.process.dns.max_retries_exceeded",
01652                      RECD_INT, RECP_PERSISTENT, (int) dns_max_retries_exceeded_stat, RecRawStatSyncSum);
01653 
01654   RecRegisterRawStat(dns_rsb, RECT_PROCESS,
01655                      "proxy.process.dns.in_flight",
01656                      RECD_INT, RECP_NON_PERSISTENT, (int) dns_in_flight_stat, RecRawStatSyncSum);
01657 
01658 }
01659 
01660 
01661 #ifdef TS_HAS_TESTS
01662 struct DNSRegressionContinuation;
01663 typedef int (DNSRegressionContinuation::*DNSRegContHandler) (int, void *);
01664 
01665 struct DNSRegressionContinuation: public Continuation
01666 {
01667   int hosts;
01668   const char **hostnames;
01669   int type;
01670   int *status;
01671   int found;
01672   int tofind;
01673   int i;
01674   RegressionTest *test;
01675 
01676   int mainEvent(int event, HostEnt *he)
01677   {
01678     (void) event;
01679     if (event == DNS_EVENT_LOOKUP) {
01680       if (he) {
01681         struct in_addr in;
01682         ++found;
01683         in.s_addr = *(unsigned int *) he->ent.h_addr_list[0];
01684         rprintf(test, "host %s [%s] = %s\n", hostnames[i - 1], he->ent.h_name, inet_ntoa(in));
01685       } else {
01686         rprintf(test, "host %s not found\n", hostnames[i - 1]);
01687       }
01688     }
01689     if (i < hosts) {
01690         dnsProcessor.gethostbyname(this, hostnames[i], DNSProcessor::Options().setHostResStyle(HOST_RES_IPV4_ONLY));
01691       ++i;
01692       return EVENT_CONT;
01693     } else {
01694       if (found == tofind)
01695         *status = REGRESSION_TEST_PASSED;
01696       else
01697         *status = REGRESSION_TEST_FAILED;
01698       return EVENT_DONE;
01699     }
01700   }
01701 
01702   DNSRegressionContinuation(int ahosts, int atofind, const char **ahostnames, RegressionTest *t, int atype, int *astatus)
01703    :  Continuation(new_ProxyMutex()), hosts(ahosts), hostnames(ahostnames), type(atype),
01704       status(astatus), found(0), tofind(atofind), i(0), test(t) {
01705     SET_HANDLER((DNSRegContHandler) & DNSRegressionContinuation::mainEvent);
01706   }
01707 };
01708 
01709 static const char *dns_test_hosts[] = {
01710   "www.apple.com",
01711   "www.ibm.com",
01712   "www.microsoft.com",
01713   "www.coke.com"
01714 };
01715 
01716 REGRESSION_TEST(DNS) (RegressionTest *t, int atype, int *pstatus) {
01717   eventProcessor.schedule_in(new DNSRegressionContinuation(4, 4, dns_test_hosts, t, atype, pstatus),
01718                              HRTIME_SECONDS(1));
01719 }
01720 
01721 #endif