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 }