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 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 #include "ink_platform.h"
00069 #include "ink_defs.h"
00070 
00071 #include <sys/types.h>
00072 #include <sys/param.h>
00073 #include <sys/socket.h>
00074 #include <sys/time.h>
00075 #include <netinet/in.h>
00076 #include <arpa/inet.h>
00077 #include <arpa/nameser.h>
00078 #ifdef HAVE_ARPA_NAMESER_COMPAT_H
00079 #include <arpa/nameser_compat.h>
00080 #endif
00081 #include <stdio.h>
00082 #include <ctype.h>
00083 #include <resolv.h>
00084 #include <unistd.h>
00085 #include <stdlib.h>
00086 #include <string.h>
00087 
00088 #include "ink_string.h"
00089 #include "ink_resolver.h"
00090 #include "ink_inet.h"
00091 #include "Tokenizer.h"
00092 
00093 #if !defined(isascii)           
00094 # define isascii(c) (!(c & 0200))
00095 #endif
00096 
00097 HostResPreferenceOrder const HOST_RES_DEFAULT_PREFERENCE_ORDER = {
00098   HOST_RES_PREFER_IPV4,
00099   HOST_RES_PREFER_IPV6,
00100   HOST_RES_PREFER_NONE
00101 };
00102 
00103 HostResPreferenceOrder host_res_default_preference_order;
00104 
00105 char const* const HOST_RES_PREFERENCE_STRING[N_HOST_RES_PREFERENCE] = {
00106     "only", "client", "ipv4", "ipv6"
00107 };
00108 
00109 char const* const HOST_RES_STYLE_STRING[] = {
00110   "invalid", "IPv4", "IPv4 only", "IPv6", "IPv6 only"
00111 };
00112 
00113 
00114 
00115 
00116 
00117 
00118 
00119 
00120 static void
00121 ink_res_nclose(ink_res_state statp) {
00122   if (statp->_vcsock >= 0) {
00123     (void) close(statp->_vcsock);
00124     statp->_vcsock = -1;
00125     statp->_flags &= ~(INK_RES_F_VC | INK_RES_F_CONN);
00126   }
00127 }
00128 
00129 static void
00130 ink_res_setservers(ink_res_state statp, IpEndpoint const* set, int cnt) {
00131   
00132   ink_res_nclose(statp);
00133 
00134   
00135   statp->nscount = 0;
00136 
00137   
00138 
00139 
00140 
00141   int nserv = 0;
00142   for ( IpEndpoint const* limit = set + cnt ; nserv < INK_MAXNS && set < limit ; ++set ) {
00143     IpEndpoint* dst = &statp->nsaddr_list[nserv];
00144 
00145     if (dst == set) {
00146       if (ats_is_ip(&set->sa))
00147         ++nserv;
00148     } else if (ats_ip_copy(&dst->sa, &set->sa)) {
00149       ++nserv;
00150     }
00151   }
00152   statp->nscount = nserv;
00153 }
00154 
00155 int
00156 ink_res_getservers(ink_res_state statp, sockaddr *set, int cnt) {
00157   int zret = 0; 
00158   IpEndpoint const* src = statp->nsaddr_list;
00159 
00160   for (int i = 0; i < statp->nscount && i < cnt; ++i, ++src) {
00161     if (ats_ip_copy(set, &src->sa)) {
00162       ++set;
00163       ++zret;
00164     }
00165   }
00166   return zret;
00167 }
00168 
00169 static void
00170 ink_res_setoptions(ink_res_state statp, const char *options, const char *source ATS_UNUSED)
00171 {
00172   const char *cp = options;
00173   int i;
00174 
00175 #ifdef DEBUG
00176   if (statp->options & INK_RES_DEBUG)
00177     printf(";; res_setoptions(\"%s\", \"%s\")...\n", options, source);
00178 #endif
00179   while (*cp) {
00180     
00181     while (*cp == ' ' || *cp == '\t')
00182       cp++;
00183     
00184     if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
00185       i = atoi(cp + sizeof("ndots:") - 1);
00186       if (i <= INK_RES_MAXNDOTS)
00187         statp->ndots = i;
00188       else
00189         statp->ndots = INK_RES_MAXNDOTS;
00190 #ifdef DEBUG
00191       if (statp->options & INK_RES_DEBUG)
00192         printf(";;\tndots=%d\n", statp->ndots);
00193 #endif
00194     } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
00195       i = atoi(cp + sizeof("timeout:") - 1);
00196       if (i <= INK_RES_MAXRETRANS)
00197         statp->retrans = i;
00198       else
00199         statp->retrans = INK_RES_MAXRETRANS;
00200 #ifdef DEBUG
00201       if (statp->options & INK_RES_DEBUG)
00202         printf(";;\ttimeout=%d\n", statp->retrans);
00203 #endif
00204 #ifdef  SOLARIS2
00205     } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
00206       
00207 
00208 
00209 
00210 
00211       statp->retrans = atoi(cp + sizeof("retrans:") - 1);
00212     } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
00213       
00214 
00215 
00216 
00217 
00218       statp->retry = atoi(cp + sizeof("retry:") - 1);
00219 #endif  
00220     } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
00221       i = atoi(cp + sizeof("attempts:") - 1);
00222       if (i <= INK_RES_MAXRETRY)
00223         statp->retry = i;
00224       else
00225         statp->retry = INK_RES_MAXRETRY;
00226 #ifdef DEBUG
00227       if (statp->options & INK_RES_DEBUG)
00228         printf(";;\tattempts=%d\n", statp->retry);
00229 #endif
00230     } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
00231 #ifdef DEBUG
00232       if (!(statp->options & INK_RES_DEBUG)) {
00233         printf(";; res_setoptions(\"%s\", \"%s\")..\n", options, source);
00234         statp->options |= INK_RES_DEBUG;
00235       }
00236       printf(";;\tdebug\n");
00237 #endif
00238     } else if (!strncmp(cp, "no_tld_query", sizeof("no_tld_query") - 1) ||
00239                !strncmp(cp, "no-tld-query", sizeof("no-tld-query") - 1)) {
00240       statp->options |= INK_RES_NOTLDQUERY;
00241     } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
00242       statp->options |= INK_RES_USE_INET6;
00243     } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
00244       statp->options |= INK_RES_ROTATE;
00245     } else if (!strncmp(cp, "no-check-names", sizeof("no-check-names") - 1)) {
00246       statp->options |= INK_RES_NOCHECKNAME;
00247     }
00248 #ifdef INK_RES_USE_EDNS0
00249     else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
00250       statp->options |= INK_RES_USE_EDNS0;
00251     }
00252 #endif
00253     else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
00254       statp->options |= INK_RES_USE_DNAME;
00255     }
00256     else {
00257       
00258     }
00259     
00260     while (*cp && *cp != ' ' && *cp != '\t')
00261       cp++;
00262   }
00263 }
00264 
00265 static u_int
00266 ink_res_randomid(void) {
00267   struct timeval now;
00268 
00269   gettimeofday(&now, NULL);
00270   return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
00271 }
00272 
00273 
00274 
00275 
00276 
00277 
00278 
00279 
00280 
00281 
00282 
00283 
00284 
00285 
00286 
00287 
00288 
00289 
00290 
00291 
00292 
00293 
00294 
00295 
00296 int
00297 ink_res_init(
00298   ink_res_state statp, 
00299   IpEndpoint const* pHostList, 
00300   size_t pHostListSize, 
00301   const char *pDefDomain, 
00302   const char *pSearchList, 
00303   const char *pResolvConf 
00304 ) {
00305   FILE *fp;
00306   char *cp, **pp;
00307   int n;
00308   char buf[BUFSIZ];
00309   size_t nserv = 0;
00310   int haveenv = 0;
00311   int havesearch = 0;
00312   int dots;
00313   size_t maxns = INK_MAXNS;
00314 
00315   
00316   statp->res_h_errno = 0;
00317 
00318   statp->retrans = INK_RES_TIMEOUT;
00319   statp->retry = INK_RES_DFLRETRY;
00320   statp->options = INK_RES_DEFAULT;
00321   statp->id = ink_res_randomid();
00322 
00323   statp->nscount = 0;
00324   statp->ndots = 1;
00325   statp->pfcode = 0;
00326   statp->_vcsock = -1;
00327   statp->_flags = 0;
00328   statp->qhook = NULL;
00329   statp->rhook = NULL;
00330 
00331 #ifdef  SOLARIS2
00332   
00333 
00334 
00335 
00336   {
00337     char buf[sizeof(statp->defdname)], *cp;
00338     int ret;
00339 
00340     if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
00341         (unsigned int)ret <= sizeof(buf)) {
00342       if (buf[0] == '+')
00343         buf[0] = '.';
00344       cp = strchr(buf, '.');
00345       cp = (cp == NULL) ? buf : (cp + 1);
00346       ink_strlcpy(statp->defdname, cp, sizeof(statp->defdname));
00347     }
00348   }
00349 #endif  
00350 
00351         
00352   if ((cp = getenv("LOCALDOMAIN")) != NULL) {
00353     (void)ink_strlcpy(statp->defdname, cp, sizeof(statp->defdname));
00354     haveenv++;
00355 
00356     
00357 
00358 
00359 
00360 
00361 
00362 
00363     cp = statp->defdname;
00364     pp = statp->dnsrch;
00365     *pp++ = cp;
00366     for (n = 0; *cp && pp < statp->dnsrch + INK_MAXDNSRCH; cp++) {
00367       if (*cp == '\n')  
00368         break;
00369       else if (*cp == ' ' || *cp == '\t') {
00370         *cp = 0;
00371         n = 1;
00372       } else if (n) {
00373         *pp++ = cp;
00374         n = 0;
00375         havesearch = 1;
00376       }
00377     }
00378     
00379     while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
00380       cp++;
00381     *cp = '\0';
00382     *pp++ = 0;
00383   }
00384 
00385   
00386 
00387 
00388 
00389 
00390 
00391 
00392 
00393 
00394   if (pDefDomain && '\0' != *pDefDomain && '\n' != *pDefDomain) {
00395     ink_strlcpy(statp->defdname, pDefDomain, sizeof(statp->defdname));
00396     if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
00397       *cp = '\0';
00398   }
00399   if (pSearchList && '\0' != *pSearchList && '\n' != *pSearchList) {
00400     ink_strlcpy(statp->defdname, pSearchList, sizeof(statp->defdname));
00401     if ((cp = strchr(statp->defdname, '\n')) != NULL)
00402       *cp = '\0';
00403     
00404 
00405 
00406 
00407     cp = statp->defdname;
00408     pp = statp->dnsrch;
00409     *pp++ = cp;
00410     for (n = 0; *cp && pp < statp->dnsrch + INK_MAXDNSRCH; cp++) {
00411       if (*cp == ' ' || *cp == '\t') {
00412         *cp = 0;
00413         n = 1;
00414       } else if (n) {
00415         *pp++ = cp;
00416         n = 0;
00417       }
00418     }
00419     
00420     while (*cp != '\0' && *cp != ' ' && *cp != '\t')
00421       cp++;
00422     *cp = '\0';
00423     *pp++ = 0;
00424     havesearch = 1;
00425   }
00426 
00427   
00428 
00429 
00430   if (pHostList) {
00431     if (pHostListSize > INK_MAXNS) pHostListSize = INK_MAXNS;
00432     for (
00433         ; nserv < pHostListSize
00434           && ats_is_ip(&pHostList[nserv].sa) 
00435         ; ++nserv
00436     ) {
00437       ats_ip_copy(&statp->nsaddr_list[nserv].sa, &pHostList[nserv].sa);
00438     }
00439   }
00440 
00441 #define MATCH(line, name)                       \
00442   (!strncmp(line, name, sizeof(name) - 1) &&    \
00443    (line[sizeof(name) - 1] == ' ' ||            \
00444     line[sizeof(name) - 1] == '\t'))
00445 
00446   if ((fp = fopen(pResolvConf, "r")) != NULL) {
00447     
00448     while (fgets(buf, sizeof(buf), fp) != NULL) {
00449       
00450       if (*buf == ';' || *buf == '#')
00451         continue;
00452       
00453       if (MATCH(buf, "domain")) {
00454         if (haveenv)    
00455           continue;
00456         cp = buf + sizeof("domain") - 1;
00457         while (*cp == ' ' || *cp == '\t')
00458           cp++;
00459         if ((*cp == '\0') || (*cp == '\n'))
00460           continue;
00461         ink_strlcpy(statp->defdname, cp, sizeof(statp->defdname));
00462         if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
00463           *cp = '\0';
00464         havesearch = 0;
00465         continue;
00466       }
00467       
00468       if (MATCH(buf, "search")) {
00469         if (haveenv)    
00470           continue;
00471         cp = buf + sizeof("search") - 1;
00472         while (*cp == ' ' || *cp == '\t')
00473           cp++;
00474         if ((*cp == '\0') || (*cp == '\n'))
00475           continue;
00476         ink_strlcpy(statp->defdname, cp, sizeof(statp->defdname));
00477         if ((cp = strchr(statp->defdname, '\n')) != NULL)
00478           *cp = '\0';
00479         
00480 
00481 
00482 
00483         cp = statp->defdname;
00484         pp = statp->dnsrch;
00485         *pp++ = cp;
00486         for (n = 0; *cp && pp < statp->dnsrch + INK_MAXDNSRCH; cp++) {
00487           if (*cp == ' ' || *cp == '\t') {
00488             *cp = 0;
00489             n = 1;
00490           } else if (n) {
00491             *pp++ = cp;
00492             n = 0;
00493           }
00494         }
00495         
00496         while (*cp != '\0' && *cp != ' ' && *cp != '\t')
00497           cp++;
00498         *cp = '\0';
00499         *pp++ = 0;
00500         havesearch = 1;
00501         continue;
00502       }
00503       
00504       if (MATCH(buf, "nameserver") && nserv < maxns) {
00505         struct addrinfo hints, *ai;
00506         char sbuf[NI_MAXSERV];
00507 
00508         cp = buf + sizeof("nameserver") - 1;
00509         while (*cp == ' ' || *cp == '\t')
00510           cp++;
00511         cp[strcspn(cp, ";# \t\n")] = '\0';
00512         if ((*cp != '\0') && (*cp != '\n')) {
00513           memset(&hints, 0, sizeof(hints));
00514           hints.ai_family = PF_UNSPEC;
00515           hints.ai_socktype = SOCK_DGRAM;       
00516           hints.ai_flags = AI_NUMERICHOST;
00517           sprintf(sbuf, "%d", NAMESERVER_PORT);
00518           if (getaddrinfo(cp, sbuf, &hints, &ai) == 0) {
00519             if (ats_ip_copy(
00520                 &statp->nsaddr_list[nserv].sa,
00521                 ai->ai_addr
00522             ))
00523               ++nserv;
00524             freeaddrinfo(ai);
00525           }
00526         }
00527         continue;
00528       }
00529       if (MATCH(buf, "options")) {
00530         ink_res_setoptions(statp, buf + sizeof("options") - 1, "conf");
00531         continue;
00532       }
00533     }
00534     (void) fclose(fp);
00535   }
00536 
00537   if (nserv > 0)
00538     statp->nscount = nserv;
00539 
00540   if (statp->defdname[0] == 0 && gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL)
00541     ink_strlcpy(statp->defdname, cp + 1, sizeof(statp->defdname));
00542 
00543   
00544   if (havesearch == 0) {
00545     pp = statp->dnsrch;
00546     *pp++ = statp->defdname;
00547     *pp = NULL;
00548 
00549     dots = 0;
00550     for (cp = statp->defdname; *cp; cp++)
00551       dots += (*cp == '.');
00552 
00553     cp = statp->defdname;
00554     while (pp < statp->dnsrch + INK_MAXDFLSRCH) {
00555       if (dots < INK_LOCALDOMAINPARTS)
00556         break;
00557       cp = strchr(cp, '.') + 1;    
00558       *pp++ = cp;
00559       dots--;
00560     }
00561     *pp = NULL;
00562 #ifdef DEBUG
00563     if (statp->options & INK_RES_DEBUG) {
00564       printf(";; res_init()... default dnsrch list:\n");
00565       for (pp = statp->dnsrch; *pp; pp++)
00566         printf(";;\t%s\n", *pp);
00567       printf(";;\t..END..\n");
00568     }
00569 #endif
00570   }
00571 
00572   
00573   ink_res_setservers(statp, &statp->nsaddr_list[0], statp->nscount);
00574 
00575   if ((cp = getenv("RES_OPTIONS")) != NULL)
00576     ink_res_setoptions(statp, cp, "env");
00577   statp->options |= INK_RES_INIT;
00578   return (statp->res_h_errno);
00579 }
00580 
00581 void
00582 parse_host_res_preference(char const* value, HostResPreferenceOrder order) {
00583   Tokenizer tokens(";/|");
00584   
00585   int np = 0; 
00586   bool found[N_HOST_RES_PREFERENCE];  
00587   int n; 
00588   int i; 
00589 
00590   n = tokens.Initialize(value);
00591 
00592   for ( i = 0 ; i < N_HOST_RES_PREFERENCE ; ++i )
00593     found[i] = false;
00594 
00595   for ( i = 0 ; i < n && np < N_HOST_RES_PREFERENCE_ORDER ; ++i ) {
00596     char const* elt = tokens[i];
00597     
00598     if (0 == strcasecmp(elt, HOST_RES_PREFERENCE_STRING[HOST_RES_PREFER_NONE])) {
00599       found[HOST_RES_PREFER_NONE] = true;
00600       order[np] = HOST_RES_PREFER_NONE;
00601       break;
00602     } else {
00603       
00604       HostResPreference ep = HOST_RES_PREFER_NONE;
00605       for ( int ip = HOST_RES_PREFER_NONE + 1 ; ip < N_HOST_RES_PREFERENCE ; ++ip ) {
00606         if (0 == strcasecmp(elt, HOST_RES_PREFERENCE_STRING[ip])) {
00607           ep = static_cast<HostResPreference>(ip);
00608           break;
00609         }
00610       }
00611       if (HOST_RES_PREFER_NONE != ep && !found[ep]) { 
00612         found[ep] = true;
00613         order[np++] = ep;
00614       }
00615     }
00616   }
00617 
00618   if (!found[HOST_RES_PREFER_NONE]) {
00619     
00620     if (!found[HOST_RES_PREFER_IPV4])
00621       order[np++] = HOST_RES_PREFER_IPV4;
00622     if (!found[HOST_RES_PREFER_IPV6])
00623       order[np++] = HOST_RES_PREFER_IPV6;
00624     if (np < N_HOST_RES_PREFERENCE_ORDER) 
00625       order[np] = HOST_RES_PREFER_NONE;
00626   }
00627 }      
00628 
00629 int
00630 ts_host_res_order_to_string(HostResPreferenceOrder const& order, char* out, int size)
00631 {
00632   int zret = 0;
00633   bool first = true;
00634   for ( int i = 0 ; i < N_HOST_RES_PREFERENCE_ORDER ; ++i ) {
00635     
00636 
00637 
00638 
00639 
00640     zret += snprintf(out+zret, size-zret, "%s%s", !first ? ";" : "", HOST_RES_PREFERENCE_STRING[order[i]]);
00641     if (HOST_RES_PREFER_NONE == order[i])
00642       break;
00643     first = false;
00644   }
00645   return zret;
00646 }