/* This function has to be reachable by res_data.c but not publicly. */ int __res_vinit(res_state statp, int preinit) { register FILE *fp; register char *cp, **pp; register int n; char buf[BUFSIZ]; int nserv = 0; /* number of nameserver records read from file */ int haveenv = 0; int havesearch = 0; int nsort = 0; char *net; int dots; union res_sockaddr_union u[2]; #if defined(ANDROID_CHANGES) && ANDROID_CHANGES pid_t mypid = getpid(); int use_proc_props = 0; int found_prop; char dnsProperty[PROP_VALUE_MAX]; #endif if ((statp->options & RES_INIT) != 0U) res_ndestroy(statp); if (!preinit) { statp->retrans = RES_TIMEOUT; statp->retry = RES_DFLRETRY; statp->options = RES_DEFAULT; statp->id = res_randomid(); } memset(u, 0, sizeof(u)); #ifdef USELOOPBACK u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else u[nserv].sin.sin_addr.s_addr = INADDR_ANY; #endif u[nserv].sin.sin_family = AF_INET; u[nserv].sin.sin_port = htons(NAMESERVER_PORT); #ifdef HAVE_SA_LEN u[nserv].sin.sin_len = sizeof(struct sockaddr_in); #endif nserv++; #ifdef HAS_INET6_STRUCTS #ifdef USELOOPBACK u[nserv].sin6.sin6_addr = in6addr_loopback; #else u[nserv].sin6.sin6_addr = in6addr_any; #endif u[nserv].sin6.sin6_family = AF_INET6; u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT); #ifdef HAVE_SA_LEN u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6); #endif nserv++; #endif statp->nscount = 0; statp->ndots = 1; statp->pfcode = 0; statp->_vcsock = -1; statp->_flags = 0; statp->qhook = NULL; statp->rhook = NULL; statp->_u._ext.nscount = 0; statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext)); if (statp->_u._ext.ext != NULL) { memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); } statp->nsort = 0; res_setservers(statp, u, nserv); #if 0 /* IGNORE THE ENVIRONMENT */ /* Allow user to override the local domain definition */ if ((cp = getenv("LOCALDOMAIN")) != NULL) { (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* * Set search list to be blank-separated strings * from rest of env value. Permits users of LOCALDOMAIN * to still have a search list, and anyone to set the * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /* silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; havesearch = 1; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') cp++; *cp = '\0'; *pp++ = 0; } if (nserv > 0) statp->nscount = nserv; #endif #if defined(ANDROID_CHANGES) && defined(PROPERTY_SYSTEM_SUPPORT) /* READ FROM SYSTEM PROPERTIES */ dns_last_change_counter = _get_dns_change_count(); nserv = 0; for(n = 1; n <= MAX_DNS_PROPERTIES && nserv < MAXNS; n++) { char propname[PROP_NAME_MAX]; char propvalue[PROP_VALUE_MAX]; struct addrinfo hints, *ai; char sbuf[NI_MAXSERV]; const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]); /* * Check first for process-specific properties, and if those don't * exist, try the generic properties. */ found_prop = 0; if (n == 1 || use_proc_props) { snprintf(propname, sizeof(propname), "%s%d.%d", DNS_PROP_NAME_PREFIX, n, mypid); if(__system_property_get(propname, propvalue) < 1) { if (use_proc_props) { break; } } else { found_prop = 1; use_proc_props = 1; } } if (!found_prop) { snprintf(propname, sizeof(propname), "%s%d", DNS_PROP_NAME_PREFIX, n); if(__system_property_get(propname, propvalue) < 1) { break; } } cp = propvalue; while (*cp == ' ' || *cp == '\t') cp++; cp[strcspn(cp, ";# \t\n")] = '\0'; if ((*cp != '\0') && (*cp != '\n')) { memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_NUMERICHOST; sprintf(sbuf, "%u", NAMESERVER_PORT); if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && (size_t)ai->ai_addrlen <= minsiz) { if (statp->_u._ext.ext != NULL) { memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen); } if ((size_t)ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv])) { memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen); } else { statp->nsaddr_list[nserv].sin_family = 0; } freeaddrinfo(ai); nserv++; } } } /* Add the domain search list */ havesearch = load_domain_search_list(statp); #else /* !ANDROID_CHANGES - IGNORE resolv.conf in Android */ #define MATCH(line, name) \ (!strncmp(line, name, sizeof(name) - 1) && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) nserv = 0; if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if (*buf == ';' || *buf == '#') continue; /* read default domain name */ if (MATCH(buf, "domain")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("domain") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ if (MATCH(buf, "search")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("search") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strchr(statp->defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t') cp++; *cp = '\0'; *pp++ = 0; havesearch = 1; continue; } /* read nameservers to query */ if (MATCH(buf, "nameserver") && nserv < MAXNS) { struct addrinfo hints, *ai; char sbuf[NI_MAXSERV]; const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]); cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; cp[strcspn(cp, ";# \t\n")] = '\0'; if ((*cp != '\0') && (*cp != '\n')) { memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_NUMERICHOST; sprintf(sbuf, "%u", NAMESERVER_PORT); if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && ai->ai_addrlen <= minsiz) { if (statp->_u._ext.ext != NULL) { memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen); } if (ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv])) { memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen); } else statp->nsaddr_list[nserv].sin_family = 0; freeaddrinfo(ai); nserv++; } } continue; } if (MATCH(buf, "sortlist")) { struct in_addr a; cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '\n' || *cp == ';') break; net = cp; while (*cp && !ISSORTMASK(*cp) && *cp != ';' && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; while (*cp && *cp != ';' && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].mask = a.s_addr; } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } nsort++; } *cp = n; } continue; } if (MATCH(buf, "options")) { res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } } if (nserv > 0) statp->nscount = nserv; statp->nsort = nsort; (void) fclose(fp); } #endif /* !ANDROID_CHANGES */ /* * Last chance to get a nameserver. This should not normally * be necessary */ #ifdef NO_RESOLV_CONF if(nserv == 0) nserv = get_nameservers(statp); #endif if (statp->defdname[0] == 0 && gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) strcpy(statp->defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { pp = statp->dnsrch; *pp++ = statp->defdname; *pp = NULL; dots = 0; for (cp = statp->defdname; *cp; cp++) dots += (*cp == '.'); cp = statp->defdname; while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = strchr(cp, '.') + 1; /* we know there is one */ *pp++ = cp; dots--; } *pp = NULL; #ifdef DEBUG if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } #endif } if ((cp = getenv("RES_OPTIONS")) != NULL) res_setoptions(statp, cp, "env"); if (nserv > 0) { statp->nscount = nserv; statp->options |= RES_INIT; } return (0); }
/* This function has to be reachable by res_data.c but not publically. */ int __res_vinit(res_state statp, int preinit) { FILE *fp; char *cp, **pp; int n; char buf[BUFSIZ]; int nserv = 0; /* number of nameservers read from file */ int have_serv6 = 0; int haveenv = 0; int havesearch = 0; #ifdef RESOLVSORT int nsort = 0; char *net; #endif #ifndef RFC1535 int dots; #endif #ifdef _LIBC statp->_u._ext.initstamp = __res_initstamp; #endif if (!preinit) { statp->retrans = RES_TIMEOUT; statp->retry = RES_DFLRETRY; statp->options = RES_DEFAULT; statp->id = res_randomid(); } statp->nscount = 0; statp->ndots = 1; statp->pfcode = 0; statp->_vcsock = -1; statp->_flags = 0; statp->qhook = NULL; statp->rhook = NULL; statp->_u._ext.nscount = 0; for (n = 0; n < MAXNS; n++) statp->_u._ext.nsaddrs[n] = NULL; /* Allow user to override the local domain definition */ if ((cp = getenv("LOCALDOMAIN")) != NULL) { (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* * Set search list to be blank-separated strings * from rest of env value. Permits users of LOCALDOMAIN * to still have a search list, and anyone to set the * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /* silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; havesearch = 1; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') cp++; *cp = '\0'; *pp++ = 0; } #define MATCH(line, name) \ (!strncmp(line, name, sizeof(name) - 1) && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) if ((fp = fopen(_PATH_RESCONF, "rce")) != NULL) { /* No threads use this stream. */ __fsetlocking (fp, FSETLOCKING_BYCALLER); /* read the config file */ while (__fgets_unlocked(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if (*buf == ';' || *buf == '#') continue; /* read default domain name */ if (MATCH(buf, "domain")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("domain") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ if (MATCH(buf, "search")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("search") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strchr(statp->defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t') cp++; *cp = '\0'; *pp++ = 0; havesearch = 1; continue; } /* read nameservers to query */ if (MATCH(buf, "nameserver") && nserv < MAXNS) { struct in_addr a; cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp != '\0') && (*cp != '\n') && __inet_aton(cp, &a)) { statp->nsaddr_list[nserv].sin_addr = a; statp->nsaddr_list[nserv].sin_family = AF_INET; statp->nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT); nserv++; #ifdef _LIBC } else { struct in6_addr a6; char *el; if ((el = strpbrk(cp, " \t\n")) != NULL) *el = '\0'; if ((el = strchr(cp, SCOPE_DELIMITER)) != NULL) *el = '\0'; if ((*cp != '\0') && (__inet_pton(AF_INET6, cp, &a6) > 0)) { struct sockaddr_in6 *sa6; sa6 = malloc(sizeof(*sa6)); if (sa6 != NULL) { sa6->sin6_family = AF_INET6; sa6->sin6_port = htons(NAMESERVER_PORT); sa6->sin6_flowinfo = 0; sa6->sin6_addr = a6; if (__glibc_likely (el == NULL)) sa6->sin6_scope_id = 0; else { int try_numericscope = 1; if (IN6_IS_ADDR_LINKLOCAL (&a6) || IN6_IS_ADDR_MC_LINKLOCAL (&a6)) { sa6->sin6_scope_id = __if_nametoindex (el + 1); if (sa6->sin6_scope_id != 0) try_numericscope = 0; } if (try_numericscope) { char *end; sa6->sin6_scope_id = (uint32_t) strtoul (el + 1, &end, 10); if (*end != '\0') sa6->sin6_scope_id = 0; } } statp->nsaddr_list[nserv].sin_family = 0; statp->_u._ext.nsaddrs[nserv] = sa6; statp->_u._ext.nssocks[nserv] = -1; have_serv6 = 1; nserv++; } } #endif } continue; } #ifdef RESOLVSORT if (MATCH(buf, "sortlist")) { struct in_addr a; cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '\n' || *cp == ';') break; net = cp; while (*cp && !ISSORTMASK(*cp) && *cp != ';' && isascii(*cp) && !isspace(*cp)) cp++; n = *cp; *cp = 0; if (__inet_aton(net, &a)) { statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; while (*cp && *cp != ';' && isascii(*cp) && !isspace(*cp)) cp++; n = *cp; *cp = 0; if (__inet_aton(net, &a)) { statp->sort_list[nsort].mask = a.s_addr; } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } nsort++; } *cp = n; } continue; } #endif if (MATCH(buf, "options")) { res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } } statp->nscount = nserv; #ifdef _LIBC if (have_serv6) { /* We try IPv6 servers again. */ statp->ipv6_unavail = false; } #endif #ifdef RESOLVSORT statp->nsort = nsort; #endif (void) fclose(fp); } if (__builtin_expect(statp->nscount == 0, 0)) { statp->nsaddr.sin_addr = __inet_makeaddr(IN_LOOPBACKNET, 1); statp->nsaddr.sin_family = AF_INET; statp->nsaddr.sin_port = htons(NAMESERVER_PORT); statp->nscount = 1; } if (statp->defdname[0] == 0 && __gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) strcpy(statp->defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { pp = statp->dnsrch; *pp++ = statp->defdname; *pp = NULL; #ifndef RFC1535 dots = 0; for (cp = statp->defdname; *cp; cp++) dots += (*cp == '.'); cp = statp->defdname; while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = __rawmemchr(cp, '.') + 1; /* we know there is one */ *pp++ = cp; dots--; } *pp = NULL; #ifdef DEBUG if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } #endif #endif /* !RFC1535 */ } if ((cp = getenv("RES_OPTIONS")) != NULL) res_setoptions(statp, cp, "env"); statp->options |= RES_INIT; return (0); }
/*% This function has to be reachable by res_data.c but not publically. */ int __res_vinit(res_state statp, int preinit) { register FILE *fp; register char *cp, **pp; register int n; char path[PATH_MAX]; char buf[BUFSIZ]; int nserv = 0; /*%< number of nameserver records read from file */ int haveenv = 0; int havesearch = 0; #ifdef RESOLVSORT int nsort = 0; char *net; #endif int dots; union res_sockaddr_union u[2]; int maxns = MAXNS; RES_SET_H_ERRNO(statp, 0); if (statp->_u._ext.ext != NULL) res_ndestroy(statp); if (!preinit) { statp->retrans = RES_TIMEOUT; statp->retry = RES_DFLRETRY; statp->options = RES_DEFAULT; res_rndinit(statp); statp->id = res_nrandomid(statp); } memset(u, 0, sizeof(u)); #ifdef USELOOPBACK u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else u[nserv].sin.sin_addr.s_addr = INADDR_ANY; #endif u[nserv].sin.sin_family = AF_INET; u[nserv].sin.sin_port = htons(NAMESERVER_PORT); #ifdef HAVE_SA_LEN u[nserv].sin.sin_len = sizeof(struct sockaddr_in); #endif nserv++; #ifdef HAS_INET6_STRUCTS #ifdef USELOOPBACK u[nserv].sin6.sin6_addr = in6addr_loopback; #else u[nserv].sin6.sin6_addr = in6addr_any; #endif u[nserv].sin6.sin6_family = AF_INET6; u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT); #ifdef HAVE_SA_LEN u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6); #endif nserv++; #endif statp->nscount = 0; statp->ndots = 1; statp->pfcode = 0; statp->_vcsock = -1; statp->_flags = 0; statp->qhook = NULL; statp->rhook = NULL; statp->_u._ext.nscount = 0; statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext)); if (statp->_u._ext.ext != NULL) { memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); } else { /* * Historically res_init() rarely, if at all, failed. * Examples and applications exist which do not check * our return code. Furthermore several applications * simply call us to get the systems domainname. So * rather then immediately fail here we store the * failure, which is returned later, in h_errno. And * prevent the collection of 'nameserver' information * by setting maxns to 0. Thus applications that fail * to check our return code wont be able to make * queries anyhow. */ RES_SET_H_ERRNO(statp, NETDB_INTERNAL); maxns = 0; } #ifdef RESOLVSORT statp->nsort = 0; #endif res_setservers(statp, u, nserv); #ifdef SOLARIS2 /* * The old libresolv derived the defaultdomain from NIS/NIS+. * We want to keep this behaviour */ { char buf[sizeof(statp->defdname)], *cp; int ret; if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 && (unsigned int)ret <= sizeof(buf)) { if (buf[0] == '+') buf[0] = '.'; cp = strchr(buf, '.'); cp = (cp == NULL) ? buf : (cp + 1); strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; } } #endif /* SOLARIS2 */ /* Allow user to override the local domain definition */ if ((cp = getenv("LOCALDOMAIN")) != NULL) { (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* * Set search list to be blank-separated strings * from rest of env value. Permits users of LOCALDOMAIN * to still have a search list, and anyone to set the * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /*%< silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; havesearch = 1; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') cp++; *cp = '\0'; *pp++ = 0; } #define MATCH(line, name) \ (!strncmp(line, name, sizeof(name) - 1) && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) if (find_directory(B_COMMON_SETTINGS_DIRECTORY, -1, false, path, sizeof(path)) == B_OK) strlcat(path, "/network/resolv.conf", sizeof(path)); nserv = 0; if ((fp = fopen(path, "r")) != NULL) { /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if (*buf == ';' || *buf == '#') continue; /* read default domain name */ if (MATCH(buf, "domain")) { if (haveenv) /*%< skip if have from environ */ continue; cp = buf + sizeof("domain") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ if (MATCH(buf, "search")) { if (haveenv) /*%< skip if have from environ */ continue; cp = buf + sizeof("search") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strchr(statp->defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t') cp++; *cp = '\0'; *pp++ = 0; havesearch = 1; continue; } /* read nameservers to query */ if (MATCH(buf, "nameserver") && nserv < maxns) { struct addrinfo hints, *ai; char sbuf[NI_MAXSERV]; const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]); cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; cp[strcspn(cp, ";# \t\n")] = '\0'; if ((*cp != '\0') && (*cp != '\n')) { memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_NUMERICHOST; sprintf(sbuf, "%u", NAMESERVER_PORT); if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && ai->ai_addrlen <= minsiz) { if (statp->_u._ext.ext != NULL) { memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen); } if (ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv])) { memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen); } else statp->nsaddr_list[nserv].sin_family = 0; freeaddrinfo(ai); nserv++; } } continue; } #ifdef RESOLVSORT if (MATCH(buf, "sortlist")) { struct in_addr a; cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '\n' || *cp == ';') break; net = cp; while (*cp && !ISSORTMASK(*cp) && *cp != ';' && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; while (*cp && *cp != ';' && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].mask = a.s_addr; } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } nsort++; } *cp = n; } continue; } #endif if (MATCH(buf, "options")) { res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } } if (nserv > 0) statp->nscount = nserv; #ifdef RESOLVSORT statp->nsort = nsort; #endif (void) fclose(fp); } /* * Last chance to get a nameserver. This should not normally * be necessary */ #ifdef NO_RESOLV_CONF if(nserv == 0) nserv = get_nameservers(statp); #endif if (statp->defdname[0] == 0 && gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) strcpy(statp->defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { pp = statp->dnsrch; *pp++ = statp->defdname; *pp = NULL; dots = 0; for (cp = statp->defdname; *cp; cp++) dots += (*cp == '.'); cp = statp->defdname; while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = strchr(cp, '.') + 1; /*%< we know there is one */ *pp++ = cp; dots--; } *pp = NULL; #ifdef DEBUG if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } #endif } if ((cp = getenv("RES_OPTIONS")) != NULL) res_setoptions(statp, cp, "env"); statp->options |= RES_INIT; return (statp->res_h_errno); }
int res_vinit_from_file(res_state statp, int preinit, char *resconf_file) { register FILE *fp; register char *cp, **pp; register int n; char buf[BUFSIZ]; int nserv = 0; /* number of nameserver records read from file */ int haveenv = 0; int havesearch = 0; int isresdefault = 0; unsigned short port; /* HOST BYTE ORDER */ unsigned int i, total_timeout; #ifdef RESOLVSORT int nsort = 0; char *net; #endif int dots; port = NS_DEFAULTPORT; total_timeout = 0; if (!preinit) { statp->retrans = RES_TIMEOUT; statp->retry = RES_DFLRETRY; statp->options = RES_DEFAULT; statp->id = res_randomid(); } if ((statp->options & RES_INIT) != 0) res_ndestroy(statp); /* N.B. we allocate a new statp->_u._ext.ext below */ /* make sure version is set */ statp->_pad = 9; statp->nscount = 0; if ((resconf_file == NULL) || (!strcmp(resconf_file, _PATH_RESCONF))) { isresdefault = 1; #ifdef USELOOPBACK statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else statp->nsaddr.sin_addr.s_addr = INADDR_ANY; #endif statp->nsaddr.sin_family = AF_INET; statp->nsaddr.sin_port = htons(NS_DEFAULTPORT); #ifdef HAVE_SA_LEN statp->nsaddr.sin_len = sizeof(struct sockaddr_in); #endif statp->nscount = 1; /* * Force loopback queries to use TCP * so we don't take a timeout if named isn't running. */ statp->options |= RES_USEVC; } statp->ndots = 1; statp->pfcode = 0; statp->_vcsock = -1; statp->_flags = 0; statp->qhook = NULL; statp->rhook = NULL; statp->_u._ext.nscount = 0; statp->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext)); if (statp->_u._ext.ext != NULL) { memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); strcpy(statp->_u._ext.ext->bsuffix, "ip6.arpa"); } #ifdef RESOLVSORT statp->nsort = 0; #endif /* Allow user to override the local domain definition */ cp = getenv("LOCALDOMAIN"); if ((cp != NULL) && (isresdefault != 0)) { (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* * Set search list to be blank-separated strings * from rest of env value. Permits users of LOCALDOMAIN * to still have a search list, and anyone to set the * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') break; else if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n != 0) { *pp++ = cp; n = 0; havesearch = 1; } } /* null terminate last domain if there are excess */ while ((*cp != '\0') && (*cp != ' ') && (*cp != '\t') && (*cp != '\n')) cp++; *cp = '\0'; *pp++ = 0; } #define MATCH(line, name) \ (!strncmp(line, name, sizeof(name) - 1) && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) if (resconf_file == NULL) resconf_file = _PATH_RESCONF; if ((fp = fopen(resconf_file, "r")) != NULL) { /* look for port number */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if (*buf == ';' || *buf == '#') continue; /* read default domain name */ if (MATCH(buf, "port")) { cp = buf + sizeof("port") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; port = atoi(cp); break; } } fclose(fp); } if ((fp = fopen(resconf_file, "r")) != NULL) { /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if ((*buf == ';') || (*buf == '#')) continue; /* read default domain name */ if (MATCH(buf, "domain")) { /* skip if have from environ */ if (haveenv) continue; cp = buf + sizeof("domain") - 1; while ((*cp == ' ') || (*cp == '\t')) cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; cp = strpbrk(statp->defdname, " \t\n"); if (cp != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ if (MATCH(buf, "search")) { /* skip if have from environ */ if (haveenv) continue; cp = buf + sizeof("search") - 1; while ((*cp == ' ') || (*cp == '\t')) cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; cp = strchr(statp->defdname, '\n'); if (cp != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if ((*cp == ' ') || (*cp == '\t')) { *cp = 0; n = 1; } else if (n != 0) { *pp++ = cp; n = 0; } } /* null terminate last domain if there are excess */ while ((*cp != '\0') && (*cp != ' ') && (*cp != '\t')) cp++; *cp = '\0'; *pp++ = 0; havesearch = 1; continue; } /* read nameservers to query */ if (MATCH(buf, "nameserver") && (nserv < MAXNS)) { #ifndef __APPLE__ struct addrinfo hints, *ai; #endif int dotcount, semicount, status; struct in_addr addr4; struct sockaddr_in sin4; struct in6_addr addr6; struct sockaddr_in6 sin6; unsigned short aport; /* HOST BYTE ORDER */ char *lastdot, *checkp; char sbuf[NI_MAXSERV]; #ifndef __APPLE__ const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]); #endif cp = buf + sizeof("nameserver") - 1; while ((*cp == ' ') || (*cp == '\t')) cp++; cp[strcspn(cp, ";# \t\n")] = '\0'; if ((*cp != '\0') && (*cp != '\n')) { #ifndef __APPLE__ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_NUMERICHOST; #endif dotcount = 0; semicount = 0; lastdot = NULL; aport = port; for (checkp = cp; *checkp != '\0'; checkp++) { if (*checkp == ':') semicount++; else if (*checkp == '.') { dotcount++; lastdot = checkp; } } if ((dotcount == 4) || ((semicount > 0) && (lastdot != NULL))) { aport = atoi(lastdot + 1); if (aport == 0) aport = port; *lastdot = '\0'; } sprintf(sbuf, "%u", aport); #ifdef __APPLE__ memset(&addr4, 0, sizeof(struct in_addr)); memset(&sin4, 0, sizeof(struct sockaddr_in)); memset(&addr6, 0, sizeof(struct in6_addr)); memset(&sin6, 0, sizeof(struct sockaddr_in6)); status = inet_pton(AF_INET6, cp, &addr6); if (status == 1) { sin6.sin6_addr = addr6; sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(aport); sin6.sin6_len = sizeof(struct sockaddr_in6); if (statp->_u._ext.ext != NULL) { memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &sin6, sizeof(struct sockaddr_in6)); } statp->nsaddr_list[nserv].sin_family = 0; nserv++; } else { status = inet_pton(AF_INET, cp, &addr4); if (status == 1) { sin4.sin_addr = addr4; sin4.sin_family = AF_INET; sin4.sin_port = htons(port); sin4.sin_len = sizeof(struct sockaddr_in); if (statp->_u._ext.ext != NULL) { memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &sin4, sizeof(struct sockaddr_in)); } memcpy(&statp->nsaddr_list[nserv], &sin4, sizeof(struct sockaddr_in)); nserv++; } } #else if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && ai->ai_addrlen <= minsiz) { if (statp->_u._ext.ext != NULL) { memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen); } if (ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv])) { memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen); } else { statp->nsaddr_list[nserv].sin_family = 0; } freeaddrinfo(ai); nserv++; } #endif } continue; } #ifdef RESOLVSORT if (MATCH(buf, "sortlist")) { struct in_addr a; cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { while ((*cp == ' ') || (*cp == '\t')) cp++; if ((*cp == '\0') || (*cp == '\n') || (*cp == ';')) break; net = cp; while (*cp && !ISSORTMASK(*cp) && (*cp != ';') && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; while (*cp && (*cp != ';') && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].mask = a.s_addr; } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } nsort++; } *cp = n; } continue; } #endif if (MATCH(buf, "options")) { res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } if (MATCH(buf, "timeout")) { cp = buf + sizeof("timeout") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; i = atoi(cp); if (i > RES_MAXRETRANS) i = RES_MAXRETRANS; total_timeout = i; continue; } } if (nserv > 1) statp->nscount = nserv; #ifdef RESOLVSORT statp->nsort = nsort; #endif fclose(fp); } /* * Last chance to get a nameserver. This should not normally * be necessary */ #ifdef NO_RESOLV_CONF if(nserv == 0) nserv = get_nameservers(statp); #endif if (isresdefault != 0) { if ((statp->defdname[0] == 0) && (gethostname(buf, sizeof(statp->defdname) - 1) == 0) && ((cp = strchr(buf, '.')) != NULL)) { strcpy(statp->defdname, cp + 1); } } /* find components of local domain that might be searched */ if (havesearch == 0) { pp = statp->dnsrch; *pp++ = statp->defdname; *pp = NULL; dots = 0; for (cp = statp->defdname; *cp; cp++) { if (*cp == '.') dots++; } /* Back up over any trailing dots and cut them out of the name */ for (cp--; (cp >= statp->defdname) && (*cp == '.'); cp--) { *cp = '\0'; dots--; } cp = statp->defdname; while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; /* we know there is a dot */ cp = strchr(cp, '.') + 1; *pp++ = cp; dots--; } *pp = NULL; #ifdef DEBUG if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } #endif } cp = getenv("RES_OPTIONS"); if ((cp != NULL) && (isresdefault != 0)) { res_setoptions(statp, cp, "env"); } #ifdef __APPLE__ /* * Post processing to set the timeout value. */ if (total_timeout != 0) { /* Timeout was set with a "timeout" line in the file */ statp->retrans = total_timeout; } else { /* * Timeout is default, or was set with "options timeout:" * This is a per-select timeout value. Calculate total timeout * and set statp->restrans which we (Apple) use to indicate * total time allowed for a query to be resolved. */ total_timeout = statp->retrans * (statp->retry + 1) * statp->nscount; statp->retrans = total_timeout; } #endif statp->options |= RES_INIT; return (0); }
/* * Set up default settings. If the configuration file exist, the values * there will have precedence. Otherwise, the server address is set to * INADDR_ANY and the default domain name comes from the gethostname(). * * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 * rather than INADDR_ANY ("0.0.0.0") as the default name server address * since it was noted that INADDR_ANY actually meant ``the first interface * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, * it had to be "up" in order for you to reach your own name server. It * was later decided that since the recommended practice is to always * install local static routes through 127.0.0.1 for all your network * interfaces, that we could solve this problem without a code change. * * The configuration file should always be used, since it is the only way * to specify a default domain. If you are running a server on your local * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" * in the configuration file. * * Return 0 if completes successfully, -1 on error */ int res_init() { register FILE *fp; register char *cp, **pp; register int n; char buf[MAXDNAME]; int nserv = 0; /* number of nameserver records read from file */ int haveenv = 0; int havesearch = 0; #ifdef RESOLVSORT int nsort = 0; char *net; #endif #ifndef RFC1535 int dots; #endif /* * These three fields used to be statically initialized. This made * it hard to use this code in a shared library. It is necessary, * now that we're doing dynamic initialization here, that we preserve * the old semantics: if an application modifies one of these three * fields of _res before res_init() is called, res_init() will not * alter them. Of course, if an application is setting them to * _zero_ before calling res_init(), hoping to override what used * to be the static default, we can't detect it and unexpected results * will follow. Zero for any of these fields would make no sense, * so one can safely assume that the applications were already getting * unexpected results. * * _res.options is tricky since some apps were known to diddle the bits * before res_init() was first called. We can't replicate that semantic * with dynamic initialization (they may have turned bits off that are * set in RES_DEFAULT). Our solution is to declare such applications * "broken". They could fool us by setting RES_INIT but none do (yet). */ if (!_res.retrans) _res.retrans = RES_TIMEOUT; if (!_res.retry) _res.retry = 4; if (!(_res.options & RES_INIT)) _res.options = RES_DEFAULT; /* * This one used to initialize implicitly to zero, so unless the app * has set it to something in particular, we can randomize it now. */ if (!_res.id) _res.id = res_randomid(); #ifdef USELOOPBACK _res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else _res.nsaddr.sin_addr.s_addr = INADDR_ANY; #endif _res.nsaddr.sin_family = AF_INET; _res.nsaddr.sin_port = htons(NAMESERVER_PORT); _res.nscount = 1; _res.ndots = 1; _res.pfcode = 0; /* Allow user to override the local domain definition */ if (issetugid() == 0 && (cp = getenv("LOCALDOMAIN")) != NULL) { (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); _res.defdname[sizeof(_res.defdname) - 1] = '\0'; haveenv++; /* * Set search list to be blank-separated strings * from rest of env value. Permits users of LOCALDOMAIN * to still have a search list, and anyone to set the * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ cp = _res.defdname; pp = _res.dnsrch; *pp++ = cp; for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /* silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; havesearch = 1; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') cp++; *cp = '\0'; *pp++ = 0; } #define MATCH(line, name) \ (!strncmp(line, name, sizeof(name) - 1) && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if (*buf == ';' || *buf == '#') continue; /* read default domain name */ if (MATCH(buf, "domain")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("domain") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); _res.defdname[sizeof(_res.defdname) - 1] = '\0'; if ((cp = strpbrk(_res.defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ if (MATCH(buf, "search")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("search") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1); _res.defdname[sizeof(_res.defdname) - 1] = '\0'; if ((cp = strchr(_res.defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ cp = _res.defdname; pp = _res.dnsrch; *pp++ = cp; for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t') cp++; *cp = '\0'; *pp++ = 0; havesearch = 1; continue; } /* read nameservers to query */ if (MATCH(buf, "nameserver") && nserv < MAXNS) { struct in_addr a; cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) { _res.nsaddr_list[nserv].sin_addr = a; _res.nsaddr_list[nserv].sin_family = AF_INET; _res.nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT); nserv++; } continue; } #ifdef RESOLVSORT if (MATCH(buf, "sortlist")) { struct in_addr a; cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '\n' || *cp == ';') break; net = cp; while (*cp && !ISSORTMASK(*cp) && *cp != ';' && isascii(*cp) && !isspace(*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { _res.sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; while (*cp && *cp != ';' && isascii(*cp) && !isspace(*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { _res.sort_list[nsort].mask = a.s_addr; } else { _res.sort_list[nsort].mask = net_mask(_res.sort_list[nsort].addr); } } else { _res.sort_list[nsort].mask = net_mask(_res.sort_list[nsort].addr); } nsort++; } *cp = n; } continue; } #endif if (MATCH(buf, "options")) { res_setoptions(buf + sizeof("options") - 1, "conf"); continue; } } if (nserv > 1) _res.nscount = nserv; #ifdef RESOLVSORT _res.nsort = nsort; #endif (void) fclose(fp); } if (_res.defdname[0] == 0 && gethostname(buf, sizeof(_res.defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) strcpy(_res.defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { pp = _res.dnsrch; *pp++ = _res.defdname; *pp = NULL; #ifndef RFC1535 dots = 0; for (cp = _res.defdname; *cp; cp++) dots += (*cp == '.'); cp = _res.defdname; while (pp < _res.dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = strchr(cp, '.') + 1; /* we know there is one */ *pp++ = cp; dots--; } *pp = NULL; #ifdef DEBUG if (_res.options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); for (pp = _res.dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } #endif #endif /* !RFC1535 */ } if (issetugid()) _res.options |= RES_NOALIASES; else if ((cp = getenv("RES_OPTIONS")) != NULL) res_setoptions(cp, "env"); _res.options |= RES_INIT; return (0); }
/* This function has to be reachable by res_data.c but not publically. */ int minires_vinit(res_state statp, int preinit) { register FILE *fp; char *cp; register char **pp; register int n; char buf[BUFSIZ]; int nserv = 0; /* number of nameserver records read from file */ int haveenv = 0; int havesearch = 0; #ifdef RESOLVSORT int nsort = 0; char *net; #endif #ifndef RFC1535 int dots; #endif if (!preinit) { statp->retrans = RES_TIMEOUT; statp->retry = RES_DFLRETRY; statp->options = RES_DEFAULT; statp->id = res_randomid(); #if defined (TRACING) statp->id = trace_mr_res_randomid (statp -> id); #endif } #ifdef USELOOPBACK statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else statp->nsaddr.sin_addr.s_addr = INADDR_ANY; #endif statp->nsaddr.sin_family = AF_INET; statp->nsaddr.sin_port = htons(NAMESERVER_PORT); statp->nscount = 1; statp->ndots = 1; statp->pfcode = 0; statp->_sock = -1; statp->_flags = 0; statp->qhook = NULL; statp->rhook = NULL; /* Allow user to override the local domain definition */ if ((cp = getenv("LOCALDOMAIN")) != NULL) { (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* * Set search list to be blank-separated strings * from rest of env value. Permits users of LOCALDOMAIN * to still have a search list, and anyone to set the * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /* silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; havesearch = 1; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') cp++; *cp = '\0'; *pp++ = 0; } #define MATCH(line, name) \ (!strncmp(line, name, sizeof(name) - 1) && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { /* read the config file */ while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if (*buf == ';' || *buf == '#') continue; /* read default domain name */ if (MATCH(buf, "domain")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("domain") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ if (MATCH(buf, "search")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("search") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strchr(statp->defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t') cp++; *cp = '\0'; *pp++ = 0; havesearch = 1; continue; } /* read nameservers to query */ if (MATCH(buf, "nameserver") && nserv < MAXNS) { struct in_addr a; cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp != '\0') && (*cp != '\n') && inet_aton(cp, &a)) { statp->nsaddr_list[nserv].sin_addr = a; statp->nsaddr_list[nserv].sin_family = AF_INET; statp->nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT); nserv++; } continue; } #ifdef RESOLVSORT if (MATCH(buf, "sortlist")) { struct in_addr a; cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '\n' || *cp == ';') break; net = cp; while (*cp && !ISSORTMASK(*cp) && *cp != ';' && isascii((int)*cp) && !isspace((int)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; while (*cp && *cp != ';' && isascii((int)*cp) && !isspace((int)*cp)) cp++; n = *cp; *cp = 0; if (inet_aton(net, &a)) { statp->sort_list[nsort].mask = a.s_addr; } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } nsort++; } *cp = n; } continue; } #endif if (MATCH(buf, "options")) { res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } } if (nserv > 1) statp->nscount = nserv; #ifdef RESOLVSORT statp->nsort = nsort; #endif (void) fclose(fp); } if (statp->defdname[0] == 0 && gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) strcpy(statp->defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { pp = statp->dnsrch; *pp++ = statp->defdname; *pp = NULL; #ifndef RFC1535 dots = 0; for (cp = statp->defdname; *cp; cp++) dots += (*cp == '.'); cp = statp->defdname; while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = strchr(cp, '.') + 1; /* we know there is one */ *pp++ = cp; dots--; } *pp = NULL; if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } #endif /* !RFC1535 */ } if ((cp = getenv("RES_OPTIONS")) != NULL) res_setoptions(statp, cp, "env"); statp->options |= RES_INIT; return (0); }
/* This function has to be reachable by res_data.c but not publically. */ int __res_vinit(res_state statp, int preinit) { register FILE *fp; register char *cp, **pp; register int n; char buf[BUFSIZ]; int nserv = 0; /* number of nameserver records read from file */ #ifdef _LIBC int nservall = 0; /* number of NS records read, nserv IPv4 only */ #endif int haveenv = 0; int havesearch = 0; #ifdef RESOLVSORT int nsort = 0; char *net; #endif #ifndef RFC1535 int dots; #endif if (!preinit) { statp->retrans = RES_TIMEOUT; statp->retry = RES_DFLRETRY; statp->options = RES_DEFAULT; statp->id = res_randomid(); } #ifdef USELOOPBACK statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); #else statp->nsaddr.sin_addr.s_addr = INADDR_ANY; #endif statp->nsaddr.sin_family = AF_INET; statp->nsaddr.sin_port = htons(NAMESERVER_PORT); statp->nscount = 1; statp->ndots = 1; statp->pfcode = 0; statp->_vcsock = -1; statp->_flags = 0; statp->qhook = NULL; statp->rhook = NULL; statp->_u._ext.nsinit = 0; statp->_u._ext.nscount = 0; #ifdef _LIBC statp->_u._ext.nscount6 = 0; for (n = 0; n < MAXNS; n++) statp->_u._ext.nsaddrs[n] = NULL; #endif /* Allow user to override the local domain definition */ if ((cp = getenv("LOCALDOMAIN")) != NULL) { (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; /* * Set search list to be blank-separated strings * from rest of env value. Permits users of LOCALDOMAIN * to still have a search list, and anyone to set the * one that they want to use as an individual (even more * important now that the rfc1535 stuff restricts searches) */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == '\n') /* silly backwards compat */ break; else if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; havesearch = 1; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') cp++; *cp = '\0'; *pp++ = 0; } #define MATCH(line, name) \ (!strncmp(line, name, sizeof(name) - 1) && \ (line[sizeof(name) - 1] == ' ' || \ line[sizeof(name) - 1] == '\t')) if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { /* No threads use this stream. */ __fsetlocking (fp, FSETLOCKING_BYCALLER); /* read the config file */ while (fgets_unlocked(buf, sizeof(buf), fp) != NULL) { /* skip comments */ if (*buf == ';' || *buf == '#') continue; /* read default domain name */ if (MATCH(buf, "domain")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("domain") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) *cp = '\0'; havesearch = 0; continue; } /* set search list */ if (MATCH(buf, "search")) { if (haveenv) /* skip if have from environ */ continue; cp = buf + sizeof("search") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp == '\0') || (*cp == '\n')) continue; strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; if ((cp = strchr(statp->defdname, '\n')) != NULL) *cp = '\0'; /* * Set search list to be blank-separated strings * on rest of line. */ cp = statp->defdname; pp = statp->dnsrch; *pp++ = cp; for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { if (*cp == ' ' || *cp == '\t') { *cp = 0; n = 1; } else if (n) { *pp++ = cp; n = 0; } } /* null terminate last domain if there are excess */ while (*cp != '\0' && *cp != ' ' && *cp != '\t') cp++; *cp = '\0'; *pp++ = 0; havesearch = 1; continue; } /* read nameservers to query */ #ifdef _LIBC if (MATCH(buf, "nameserver") && nservall < MAXNS) { #else if (MATCH(buf, "nameserver") && nserv < MAXNS) { #endif struct in_addr a; cp = buf + sizeof("nameserver") - 1; while (*cp == ' ' || *cp == '\t') cp++; if ((*cp != '\0') && (*cp != '\n') && __inet_aton(cp, &a)) { statp->nsaddr_list[nserv].sin_addr = a; statp->nsaddr_list[nserv].sin_family = AF_INET; statp->nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT); nserv++; #ifdef _LIBC nservall++; } else { struct in6_addr a6; char *el; if ((el = strchr(cp, '\n')) != NULL) *el = '\0'; if ((*cp != '\0') && (inet_pton(AF_INET6, cp, &a6) > 0)) { struct sockaddr_in6 *sa6; sa6 = malloc(sizeof(*sa6)); if (sa6 != NULL) { sa6->sin6_addr = a6; sa6->sin6_family = AF_INET6; sa6->sin6_port = htons(NAMESERVER_PORT); statp->_u._ext.nsaddrs[nservall] = sa6; statp->_u._ext.nstimes[nservall] = RES_MAXTIME; statp->_u._ext.nssocks[nservall] = -1; nservall++; } } #endif } continue; } #ifdef RESOLVSORT if (MATCH(buf, "sortlist")) { struct in_addr a; cp = buf + sizeof("sortlist") - 1; while (nsort < MAXRESOLVSORT) { while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '\n' || *cp == ';') break; net = cp; while (*cp && !ISSORTMASK(*cp) && *cp != ';' && isascii(*cp) && !isspace(*cp)) cp++; n = *cp; *cp = 0; if (__inet_aton(net, &a)) { statp->sort_list[nsort].addr = a; if (ISSORTMASK(n)) { *cp++ = n; net = cp; while (*cp && *cp != ';' && isascii(*cp) && !isspace(*cp)) cp++; n = *cp; *cp = 0; if (__inet_aton(net, &a)) { statp->sort_list[nsort].mask = a.s_addr; } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } } else { statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); } nsort++; } *cp = n; } continue; } #endif if (MATCH(buf, "options")) { res_setoptions(statp, buf + sizeof("options") - 1, "conf"); continue; } } if (nserv > 1) statp->nscount = nserv; #ifdef _LIBC if (nservall - nserv > 0) statp->_u._ext.nscount6 = nservall - nserv; #endif #ifdef RESOLVSORT statp->nsort = nsort; #endif (void) fclose(fp); } if (statp->defdname[0] == 0 && __gethostname(buf, sizeof(statp->defdname) - 1) == 0 && (cp = strchr(buf, '.')) != NULL) strcpy(statp->defdname, cp + 1); /* find components of local domain that might be searched */ if (havesearch == 0) { pp = statp->dnsrch; *pp++ = statp->defdname; *pp = NULL; #ifndef RFC1535 dots = 0; for (cp = statp->defdname; *cp; cp++) dots += (*cp == '.'); cp = statp->defdname; while (pp < statp->dnsrch + MAXDFLSRCH) { if (dots < LOCALDOMAINPARTS) break; cp = __rawmemchr(cp, '.') + 1; /* we know there is one */ *pp++ = cp; dots--; } *pp = NULL; #ifdef DEBUG if (statp->options & RES_DEBUG) { printf(";; res_init()... default dnsrch list:\n"); for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); printf(";;\t..END..\n"); } #endif #endif /* !RFC1535 */ } if ((cp = getenv("RES_OPTIONS")) != NULL) res_setoptions(statp, cp, "env"); statp->options |= RES_INIT; return (0); } static void internal_function res_setoptions(res_state statp, const char *options, const char *source) { const char *cp = options; int i; #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";; res_setoptions(\"%s\", \"%s\")...\n", options, source); #endif while (*cp) { /* skip leading and inner runs of spaces */ while (*cp == ' ' || *cp == '\t') cp++; /* search for and process individual options */ if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { i = atoi(cp + sizeof("ndots:") - 1); if (i <= RES_MAXNDOTS) statp->ndots = i; else statp->ndots = RES_MAXNDOTS; #ifdef DEBUG if (statp->options & RES_DEBUG) printf(";;\tndots=%d\n", statp->ndots); #endif } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { i = atoi(cp + sizeof("timeout:") - 1); if (i <= RES_MAXRETRANS) statp->retrans = i; else statp->retrans = RES_MAXRETRANS; } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ i = atoi(cp + sizeof("attempts:") - 1); if (i <= RES_MAXRETRY) statp->retry = i; else statp->retry = RES_MAXRETRY; } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { #ifdef DEBUG if (!(statp->options & RES_DEBUG)) { printf(";; res_setoptions(\"%s\", \"%s\")..\n", options, source); statp->options |= RES_DEBUG; } printf(";;\tdebug\n"); #endif } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { statp->options |= RES_USE_INET6; } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { statp->options |= RES_ROTATE; } else if (!strncmp(cp, "no-check-names", sizeof("no-check-names") - 1)) { statp->options |= RES_NOCHECKNAME; } else { /* XXX - print a warning here? */ } /* skip to next run of spaces */ while (*cp && *cp != ' ' && *cp != '\t') cp++; } } #ifdef RESOLVSORT /* XXX - should really support CIDR which means explicit masks always. */ static u_int32_t net_mask(in) /* XXX - should really use system's version of this */ struct in_addr in; { register u_int32_t i = ntohl(in.s_addr); if (IN_CLASSA(i)) return (htonl(IN_CLASSA_NET)); else if (IN_CLASSB(i)) return (htonl(IN_CLASSB_NET)); return (htonl(IN_CLASSC_NET)); } #endif u_int res_randomid(void) { struct timeval now; __gettimeofday(&now, NULL); return (0xffff & (now.tv_sec ^ now.tv_usec ^ __getpid())); } /* * This routine is for closing the socket if a virtual circuit is used and * the program wants to close it. This provides support for endhostent() * which expects to close the socket. * * This routine is not expected to be user visible. */ void res_nclose(res_state statp) { int ns; if (statp->_vcsock >= 0) { (void) __close(statp->_vcsock); statp->_vcsock = -1; statp->_flags &= ~(RES_F_VC | RES_F_CONN); } #ifdef _LIBC for (ns = 0; ns < statp->_u._ext.nscount + statp->_u._ext.nscount6; ns++) #else for (ns = 0; ns < statp->_u._ext.nscount; ns++) #endif { if (statp->_u._ext.nssocks[ns] != -1) { (void) __close(statp->_u._ext.nssocks[ns]); statp->_u._ext.nssocks[ns] = -1; } } statp->_u._ext.nsinit = 0; }