static int init_by_resolv_conf(ares_channel channel) { FILE *fp; char *line = NULL, *p; int linesize, status, nservers = 0, nsort = 0; struct server_state *servers = NULL; struct apattern *sortlist = NULL; fp = fopen(PATH_RESOLV_CONF, "r"); if (!fp) return (errno == ENOENT) ? ARES_SUCCESS : ARES_EFILE; while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { if ((p = try_config(line, "domain")) && channel->ndomains == -1) status = config_domain(channel, p); else if ((p = try_config(line, "lookup")) && !channel->lookups) status = config_lookup(channel, p); else if ((p = try_config(line, "search")) && channel->ndomains == -1) status = set_search(channel, p); else if ((p = try_config(line, "nameserver")) && channel->nservers == -1) status = config_nameserver(&servers, &nservers, p); else if ((p = try_config(line, "sortlist")) && channel->nsort == -1) status = config_sortlist(&sortlist, &nsort, p); else if ((p = try_config(line, "options"))) status = set_options(channel, p); else status = ARES_SUCCESS; if (status != ARES_SUCCESS) break; } free(line); fclose(fp); /* Handle errors. */ if (status != ARES_EOF) { free(servers); free(sortlist); return status; } /* If we got any name server entries, fill them in. */ if (servers) { channel->servers = servers; channel->nservers = nservers; } /* If we got any sortlist entries, fill them in. */ if (sortlist) { channel->sortlist = sortlist; channel->nsort = nsort; } return ARES_SUCCESS; }
int ares__get_hostent(FILE *fp, int family, struct hostent **host) { char *line = NULL, *p, *q, **alias; char *txtaddr, *txthost, *txtalias; int status; size_t addrlen, linesize, naliases; struct ares_addr addr; struct hostent *hostent = NULL; *host = NULL; /* Assume failure */ /* Validate family */ switch (family) { case AF_INET: case AF_INET6: case AF_UNSPEC: break; default: return ARES_EBADFAMILY; } while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { /* Trim line comment. */ p = line; while (*p && (*p != '#')) p++; *p = '\0'; /* Trim trailing whitespace. */ q = p - 1; while ((q >= line) && ISSPACE(*q)) q--; *++q = '\0'; /* Skip leading whitespace. */ p = line; while (*p && ISSPACE(*p)) p++; if (!*p) /* Ignore line if empty. */ continue; /* Pointer to start of IPv4 or IPv6 address part. */ txtaddr = p; /* Advance past address part. */ while (*p && !ISSPACE(*p)) p++; if (!*p) /* Ignore line if reached end of line. */ continue; /* Null terminate address part. */ *p = '\0'; /* Advance to host name */ p++; while (*p && ISSPACE(*p)) p++; if (!*p) /* Ignore line if reached end of line. */ continue; /* Pointer to start of host name. */ txthost = p; /* Advance past host name. */ while (*p && !ISSPACE(*p)) p++; /* Pointer to start of first alias. */ txtalias = NULL; if (*p) { q = p + 1; while (*q && ISSPACE(*q)) q++; if (*q) txtalias = q; } /* Null terminate host name. */ *p = '\0'; /* find out number of aliases. */ naliases = 0; if (txtalias) { p = txtalias; while (*p) { while (*p && !ISSPACE(*p)) p++; while (*p && ISSPACE(*p)) p++; naliases++; } } /* Convert address string to network address for the requested family. */ addrlen = 0; addr.family = AF_UNSPEC; addr.addrV4.s_addr = INADDR_NONE; if ((family == AF_INET) || (family == AF_UNSPEC)) { addr.addrV4.s_addr = inet_addr(txtaddr); if (addr.addrV4.s_addr != INADDR_NONE) { /* Actual network address family and length. */ addr.family = AF_INET; addrlen = sizeof(addr.addrV4); } } if ((family == AF_INET6) || ((family == AF_UNSPEC) && (!addrlen))) { if (ares_inet_pton(AF_INET6, txtaddr, &addr.addrV6) > 0) { /* Actual network address family and length. */ addr.family = AF_INET6; addrlen = sizeof(addr.addrV6); } } if (!addrlen) /* Ignore line if invalid address string for the requested family. */ continue; /* ** Actual address family possible values are AF_INET and AF_INET6 only. */ /* Allocate memory for the hostent structure. */ hostent = malloc(sizeof(struct hostent)); if (!hostent) break; /* Initialize fields for out of memory condition. */ hostent->h_aliases = NULL; hostent->h_addr_list = NULL; /* Copy official host name. */ hostent->h_name = strdup(txthost); if (!hostent->h_name) break; /* Copy network address. */ hostent->h_addr_list = malloc(2 * sizeof(char *)); if (!hostent->h_addr_list) break; hostent->h_addr_list[1] = NULL; hostent->h_addr_list[0] = malloc(addrlen); if (!hostent->h_addr_list[0]) break; if (addr.family == AF_INET) memcpy(hostent->h_addr_list[0], &addr.addrV4, sizeof(addr.addrV4)); else memcpy(hostent->h_addr_list[0], &addr.addrV6, sizeof(addr.addrV6)); /* Copy aliases. */ hostent->h_aliases = malloc((naliases + 1) * sizeof(char *)); if (!hostent->h_aliases) break; alias = hostent->h_aliases; while (naliases) *(alias + naliases--) = NULL; *alias = NULL; while (txtalias) { p = txtalias; while (*p && !ISSPACE(*p)) p++; q = p; while (*q && ISSPACE(*q)) q++; *p = '\0'; if ((*alias = strdup(txtalias)) == NULL) break; alias++; txtalias = *q ? q : NULL; } if (txtalias) /* Alias memory allocation failure. */ break; /* Copy actual network address family and length. */ hostent->h_addrtype = addr.family; hostent->h_length = (int)addrlen; /* Free line buffer. */ free(line); /* Return hostent successfully */ *host = hostent; return ARES_SUCCESS; } /* If allocated, free line buffer. */ if (line) free(line); if (status == ARES_SUCCESS) { /* Memory allocation failure; clean up. */ if (hostent) { if (hostent->h_name) free((char *) hostent->h_name); if (hostent->h_aliases) { for (alias = hostent->h_aliases; *alias; alias++) free(*alias); free(hostent->h_aliases); } if (hostent->h_addr_list) { if (hostent->h_addr_list[0]) free(hostent->h_addr_list[0]); free(hostent->h_addr_list); } free(hostent); } return ARES_ENOMEM; } return status; }
static int init_by_resolv_conf(ares_channel channel) { #ifndef WATT32 char *line = NULL; #endif int status = -1, nservers = 0, nsort = 0; struct server_state *servers = NULL; struct apattern *sortlist = NULL; #ifdef WIN32 /* NameServer info via IPHLPAPI (IP helper API): GetNetworkParams() should be the trusted source for this. Available in Win-98/2000 and later. If that fail, fall-back to registry information. NameServer Registry: On Windows 9X, the DNS server can be found in: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer On Windows NT/2000/XP/2003: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer or HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer or HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\ NameServer or HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\ DhcpNameServer */ HKEY mykey; HKEY subkey; DWORD data_type; DWORD bytes; DWORD result; char buf[512]; win_platform platform; if (channel->nservers > -1) /* don't override ARES_OPT_SERVER */ return ARES_SUCCESS; if (get_iphlpapi_dns_info(buf,sizeof(buf)) > 0) { status = config_nameserver(&servers, &nservers, buf); if (status == ARES_SUCCESS) goto okay; } platform = ares__getplatform(); if (platform == WIN_NT) { if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &mykey ) == ERROR_SUCCESS) { RegOpenKeyEx(mykey, "Interfaces", 0, KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &subkey); if (get_res_nt(mykey, NAMESERVER, &line)) { status = config_nameserver(&servers, &nservers, line); free(line); } else if (get_res_nt(mykey, DHCPNAMESERVER, &line)) { status = config_nameserver(&servers, &nservers, line); free(line); } /* Try the interfaces */ else if (get_res_interfaces_nt(subkey, NAMESERVER, &line)) { status = config_nameserver(&servers, &nservers, line); free(line); } else if (get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line)) { status = config_nameserver(&servers, &nservers, line); free(line); } RegCloseKey(subkey); RegCloseKey(mykey); } } else if (platform == WIN_9X) { if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, WIN_NS_9X, 0, KEY_READ, &mykey ) == ERROR_SUCCESS) { if ((result = RegQueryValueEx( mykey, NAMESERVER, NULL, &data_type, NULL, &bytes ) ) == ERROR_SUCCESS || result == ERROR_MORE_DATA) { if (bytes) { line = malloc(bytes+1); if (RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type, (unsigned char *)line, &bytes) == ERROR_SUCCESS) { status = config_nameserver(&servers, &nservers, line); } free(line); } } } RegCloseKey(mykey); } if (status == ARES_SUCCESS) status = ARES_EOF; else /* Catch the case when all the above checks fail (which happens when there is no network card or the cable is unplugged) */ status = ARES_EFILE; #elif defined(__riscos__) /* Under RISC OS, name servers are listed in the system variable Inet$Resolvers, space separated. */ line = getenv("Inet$Resolvers"); status = ARES_EOF; if (line) { char *resolvers = strdup(line), *pos, *space; if (!resolvers) return ARES_ENOMEM; pos = resolvers; do { space = strchr(pos, ' '); if (space) *space = '\0'; status = config_nameserver(&servers, &nservers, pos); if (status != ARES_SUCCESS) break; pos = space + 1; } while (space); if (status == ARES_SUCCESS) status = ARES_EOF; free(resolvers); } #elif defined(WATT32) int i; sock_init(); for (i = 0; def_nameservers[i]; i++) ; if (i == 0) return ARES_SUCCESS; /* use localhost DNS server */ nservers = i; servers = calloc(i, sizeof(struct server_state)); if (!servers) return ARES_ENOMEM; for (i = 0; def_nameservers[i]; i++) { servers[i].addr.addrV4.s_addr = htonl(def_nameservers[i]); servers[i].addr.family = AF_INET; } status = ARES_EOF; #elif defined(ANDROID) char value[PROP_VALUE_MAX]=""; __system_property_get("net.dns1", value); status = config_nameserver(&servers, &nservers, value); if (status == ARES_SUCCESS) status = ARES_EOF; #else { char *p; FILE *fp; size_t linesize; int error; /* Don't read resolv.conf and friends if we don't have to */ if (ARES_CONFIG_CHECK(channel)) return ARES_SUCCESS; fp = fopen(PATH_RESOLV_CONF, "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { if ((p = try_config(line, "domain", ';'))) status = config_domain(channel, p); else if ((p = try_config(line, "lookup", ';')) && !channel->lookups) status = config_lookup(channel, p, "bind", "file"); else if ((p = try_config(line, "search", ';'))) status = set_search(channel, p); else if ((p = try_config(line, "nameserver", ';')) && channel->nservers == -1) status = config_nameserver(&servers, &nservers, p); else if ((p = try_config(line, "sortlist", ';')) && channel->nsort == -1) status = config_sortlist(&sortlist, &nsort, p); else if ((p = try_config(line, "options", ';'))) status = set_options(channel, p); else status = ARES_SUCCESS; if (status != ARES_SUCCESS) break; } fclose(fp); } else { error = ERRNO; switch(error) { case ENOENT: case ESRCH: status = ARES_EOF; break; default: DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", error, strerror(error))); DEBUGF(fprintf(stderr, "Error opening file: %s\n", PATH_RESOLV_CONF)); status = ARES_EFILE; } } if ((status == ARES_EOF) && (!channel->lookups)) { /* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */ fp = fopen("/etc/nsswitch.conf", "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { if ((p = try_config(line, "hosts:", '\0')) && !channel->lookups) /* ignore errors */ (void)config_lookup(channel, p, "dns", "files"); } fclose(fp); } else { error = ERRNO; switch(error) { case ENOENT: case ESRCH: status = ARES_EOF; break; default: DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", error, strerror(error))); DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/nsswitch.conf")); status = ARES_EFILE; } } } if ((status == ARES_EOF) && (!channel->lookups)) { /* Linux / GNU libc 2.x and possibly others have host.conf */ fp = fopen("/etc/host.conf", "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { if ((p = try_config(line, "order", '\0')) && !channel->lookups) /* ignore errors */ (void)config_lookup(channel, p, "bind", "hosts"); } fclose(fp); } else { error = ERRNO; switch(error) { case ENOENT: case ESRCH: status = ARES_EOF; break; default: DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", error, strerror(error))); DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/host.conf")); status = ARES_EFILE; } } } if ((status == ARES_EOF) && (!channel->lookups)) { /* Tru64 uses /etc/svc.conf */ fp = fopen("/etc/svc.conf", "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { if ((p = try_config(line, "hosts=", '\0')) && !channel->lookups) /* ignore errors */ (void)config_lookup(channel, p, "bind", "local"); } fclose(fp); } else { error = ERRNO; switch(error) { case ENOENT: case ESRCH: status = ARES_EOF; break; default: DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", error, strerror(error))); DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/svc.conf")); status = ARES_EFILE; } } } if(line) free(line); } #endif /* Handle errors. */ if (status != ARES_EOF) { if (servers != NULL) free(servers); if (sortlist != NULL) free(sortlist); return status; } /* If we got any name server entries, fill them in. */ #ifdef WIN32 okay: #endif if (servers) { channel->servers = servers; channel->nservers = nservers; } /* If we got any sortlist entries, fill them in. */ if (sortlist) { channel->sortlist = sortlist; channel->nsort = nsort; } return ARES_SUCCESS; }
/* Determine if this name only yields one query. If it does, set *s to * the string we should query, in an allocated buffer. If not, set *s * to NULL. */ static int single_domain(ares_channel channel, const char *name, char **s) { size_t len = strlen(name); const char *hostaliases; FILE *fp; char *line = NULL; int linesize, status; const char *p, *q; /* If the name contains a trailing dot, then the single query is the name * sans the trailing dot. */ if (name[len - 1] == '.') { *s = strdup(name); return (*s) ? ARES_SUCCESS : ARES_ENOMEM; } if (!(channel->flags & ARES_FLAG_NOALIASES) && !strchr(name, '.')) { /* The name might be a host alias. */ #ifdef UNDER_CE hostaliases = NULL; #else hostaliases = getenv("HOSTALIASES"); #endif if (hostaliases) { fp = fopen(hostaliases, "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { if (strncasecmp(line, name, len) != 0 || !isspace((unsigned char)line[len])) continue; p = line + len; while (isspace((unsigned char)*p)) p++; if (*p) { q = p + 1; while (*q && !isspace((unsigned char)*q)) q++; *s = malloc(q - p + 1); if (*s) { memcpy(*s, p, q - p); (*s)[q - p] = 0; } free(line); fclose(fp); return (*s) ? ARES_SUCCESS : ARES_ENOMEM; } } free(line); fclose(fp); if (status != ARES_SUCCESS) return status; } } } if (channel->flags & ARES_FLAG_NOSEARCH || channel->ndomains == 0) { /* No domain search to do; just try the name as-is. */ *s = strdup(name); return (*s) ? ARES_SUCCESS : ARES_ENOMEM; } *s = NULL; return ARES_SUCCESS; }
/* Determine if this name only yields one query. If it does, set *s to * the string we should query, in an allocated buffer. If not, set *s * to NULL. */ static int single_domain(ares_channel channel, const char *name, char **s) { size_t len = strlen(name); const char *hostaliases; FILE *fp; char *line = NULL; int status; size_t linesize; const char *p, *q; int error; /* If the name contains a trailing dot, then the single query is the name * sans the trailing dot. */ if (name[len - 1] == '.') { *s = strdup(name); return (*s) ? ARES_SUCCESS : ARES_ENOMEM; } if (!(channel->flags & ARES_FLAG_NOALIASES) && !strchr(name, '.')) { /* The name might be a host alias. */ hostaliases = getenv("HOSTALIASES"); if (hostaliases) { fp = fopen(hostaliases, "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { if (strncasecmp(line, name, len) != 0 || !ISSPACE(line[len])) continue; p = line + len; while (ISSPACE(*p)) p++; if (*p) { q = p + 1; while (*q && !ISSPACE(*q)) q++; *s = malloc(q - p + 1); if (*s) { memcpy(*s, p, q - p); (*s)[q - p] = 0; } free(line); fclose(fp); return (*s) ? ARES_SUCCESS : ARES_ENOMEM; } } free(line); fclose(fp); if (status != ARES_SUCCESS) return status; } else { error = errno; switch(error) { case ENOENT: case ESRCH: break; default: DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", error, strerror(error))); DEBUGF(fprintf(stderr, "Error opening file: %s\n", hostaliases)); *s = NULL; return ARES_EFILE; } } } } if (channel->flags & ARES_FLAG_NOSEARCH || channel->ndomains == 0) { /* No domain search to do; just try the name as-is. */ *s = strdup(name); return (*s) ? ARES_SUCCESS : ARES_ENOMEM; } *s = NULL; return ARES_SUCCESS; }