📄 sres.c
字号:
}/** Update config file. * * @retval 1 if DNS server list is different from old one. * @retval 0 when otherwise successful * @retval -1 upon an error */static int sres_update_config(sres_resolver_t *res, int always, time_t now){ sres_config_t *c = NULL; sres_config_t const *previous; int retval; previous = res->res_config; if (!always && previous && now < res->res_checked) return 0; /* Try avoid checking for changes too often. */ res->res_checked = now + SRES_UPDATE_INTERVAL_SECS; if (!always && previous && sres_config_timestamp(previous) == previous->c_modified) return 0; c = sres_parse_resolv_conf(res, res->res_options); if (!c) return -1; res->res_config = c; retval = sres_config_changed_servers(c, previous); su_home_unref((su_home_t *)previous->c_home); return retval;}#if HAVE_WIN32/** Number of octets to read from a registry key at a time */#define QUERY_DATALEN 1024#define MAX_DATALEN 65535/** * Uses IP Helper IP to get DNS servers list. */static int sres_parse_win32_ip(sres_config_t *c){ int ret = -1;#if HAVE_IPHLPAPI_H DWORD dw; su_home_t *home = c->c_home; ULONG size = sizeof(FIXED_INFO); do { FIXED_INFO *info = (FIXED_INFO *)su_alloc(home, size); dw = GetNetworkParams(info, &size); if (dw == ERROR_SUCCESS) { IP_ADDR_STRING* addr = &info->DnsServerList; for (; addr; addr = addr->Next) { SU_DEBUG_3(("Adding nameserver: %s\n", addr->IpAddress.String)); sres_parse_nameserver(c, addr->IpAddress.String); } ret = 0; } su_free(home, info); } while (dw == ERROR_BUFFER_OVERFLOW);#endif return ret;}/** * Parses name servers listed in registry key 'key+lpValueName'. The * key is expected to contain a whitespace separate list of * name server IP addresses. * * @return number of server addresses added */ static int sres_parse_win32_reg_parse_dnsserver(sres_config_t *c, HKEY key, LPCTSTR lpValueName){ su_home_t *home = c->c_home; su_strlst_t *reg_dns_list; BYTE *name_servers = su_alloc(home, QUERY_DATALEN); DWORD name_servers_length = QUERY_DATALEN; int ret, servers_added = 0; /* get name servers and ... */ while((ret = RegQueryValueEx(key, lpValueName, NULL, NULL, name_servers, &name_servers_length)) == ERROR_MORE_DATA) { name_servers_length += QUERY_DATALEN; /* sanity check, upper limit for memallocs */ if (name_servers_length > MAX_DATALEN) break; name_servers = su_realloc(home, name_servers, name_servers_length); if (name_servers == NULL) { ret = ERROR_BUFFER_OVERFLOW; break; } } /* if reading the key was succesful, continue */ if (ret == ERROR_SUCCESS) { if (name_servers[0]){ int i; /* add to list */ reg_dns_list = su_strlst_split(home, (char *)name_servers, " "); for(i = 0 ; i < su_strlst_len(reg_dns_list); i++) { const char *item = su_strlst_item(reg_dns_list, i); SU_DEBUG_3(("Adding nameserver: %s (key=%s)\n", item, (char*)lpValueName)); sres_parse_nameserver(c, item); ++servers_added; } su_strlst_destroy(reg_dns_list); } } su_free(home, name_servers); return servers_added;}/** * Discover system nameservers from Windows registry. * * Refs: * - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/regqueryvalueex.asp * - http://support.microsoft.com/default.aspx?scid=kb;en-us;120642 * - http://support.microsoft.com/kb/314053/EN-US/ * - IP Helper API (possibly better way than current registry-based impl.) * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/iphlp/iphlp/ip_helper_start_page.asp */static int sres_parse_win32_reg(sres_config_t *c){ int ret = -1;#define MAX_KEY_LEN 255#define MAX_VALUE_NAME_LEN 16383 su_home_t *home = c->c_home; HKEY key_handle; #if 0 HKEY interface_key_handle; FILETIME ftime; int index, i;#endif int found = 0; char *interface_guid = su_alloc(home, MAX_VALUE_NAME_LEN);#if 0#if __MINGW32__ DWORD guid_size = QUERY_DATALEN;#else int guid_size = MAX_VALUE_NAME_LEN;#endif /* step: find interface specific nameservers * - this is currently disabled 2006/Jun (the current check might insert * multiple unnecessary nameservers to the search list) */ /* open the 'Interfaces' registry Key */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &key_handle)) { SU_DEBUG_2(("RegOpenKeyEx failed\n")); } else { index = 0; /* for each interface listed ... */ while (RegEnumKeyEx(key_handle, index, interface_guid, &guid_size, NULL,NULL,0,&ftime) == ERROR_SUCCESS){ if (RegOpenKeyEx(key_handle, interface_guid, 0, KEY_READ, &interface_key_handle) == ERROR_SUCCESS) { /* note: 'NameServer' is preferred over 'DhcpNameServer' */ found += sres_parse_win32_reg_parse_dnsserver(c, interface_key_handle, "NameServer"); if (found == 0) found += sres_parse_win32_reg_parse_dnsserver(c, interface_key_handle, "DhcpNameServer"); RegCloseKey(interface_key_handle); } else{ SU_DEBUG_2(("interface RegOpenKeyEx failed\n")); } index++; guid_size = 64; } RegCloseKey(key_handle); }#endif /* #if 0: interface-specific nameservers */ /* step: if no interface-specific nameservers are found, * check for system-wide nameservers */ if (found == 0) { if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &key_handle)) { SU_DEBUG_2(("RegOpenKeyEx failed (2)\n")); } else { found += sres_parse_win32_reg_parse_dnsserver(c, key_handle, "NameServer"); if (found == 0) found += sres_parse_win32_reg_parse_dnsserver(c, key_handle, "DhcpNameServer"); RegCloseKey(key_handle); } } SU_DEBUG_3(("Total of %d name servers found from win32 registry.\n", found)); /* return success if servers found */ if (found) ret = 0; su_free(home, interface_guid); return ret;}#endif /* HAVE_WIN32 *//** Parse /etc/resolv.conf file. * * @retval #sres_config_t structure when successful * @retval NULL upon an error * * @todo The resolv.conf directives @b sortlist and most of the options * are currently ignored. */static sres_config_t *sres_parse_resolv_conf(sres_resolver_t *res, char const **options){ sres_config_t *c = su_home_new(sizeof *c); if (c) { FILE *f; int i; f = fopen(c->c_filename = res->res_cnffile, "r"); sres_parse_config(c, f); if (f) fclose(f);#if HAVE_WIN32 /* note: no 127.0.0.1 on win32 systems */ /* on win32, query the registry for nameservers */ if (sres_parse_win32_ip(c) == 0 || sres_parse_win32_reg(c) == 0) /* success */; else /* now what? */;#else /* Use local nameserver by default */ if (c->c_nameservers[0] == NULL) sres_parse_nameserver(c, "127.0.0.1");#endif for (i = 0; c->c_nameservers[i] && i < SRES_MAX_NAMESERVERS; i++) { struct sockaddr_in *sin = (void *)c->c_nameservers[i]->ns_addr; sin->sin_port = htons(c->c_port); } sres_parse_options(c, getenv("RES_OPTIONS")); if (options) for (i = 0; options[i]; i++) sres_parse_options(c, options[i]); sres_parse_options(c, getenv("SRES_OPTIONS")); su_home_threadsafe(c->c_home); } return c;}uint16_t _sres_default_port = 53;/** Parse config file. * * @return Number of search domains, if successful. * @retval -1 upon an error (never happens). */staticint sres_parse_config(sres_config_t *c, FILE *f){ su_home_t *home = c->c_home; int line; char const *localdomain; char *search = NULL, *domain = NULL; char buf[1025]; int i = 0; localdomain = getenv("LOCALDOMAIN"); /* Default values */ c->c_opt.ndots = 1; c->c_opt.check_names = 1; c->c_opt.timeout = SRES_RETRY_INTERVAL; c->c_opt.attempts = SRES_MAX_RETRY_COUNT; c->c_port = _sres_default_port; if (f != NULL) { for (line = 1; fgets(buf, sizeof(buf), f); line++) { size_t len; char *value, *b; /* Skip whitespace at the beginning ...*/ b = buf + strspn(buf, " \t"); /* ... and at the end of line */ for (len = strlen(b); len > 0 && strchr(" \t\r\n", b[len - 1]); len--) ; if (len == 0 || b[0] == '#') /* Empty line or comment */ continue; b[len] = '\0'; len = strcspn(b, " \t"); value = b + len; value += strspn(value, " \t");#define MATCH(token) (len == strlen(token) && strncasecmp(token, b, len) == 0) if (MATCH("nameserver")) { if (sres_parse_nameserver(c, value) < 0) return -1; } else if (MATCH("domain")) { if (localdomain) /* LOCALDOMAIN overrides */ continue; if (search) su_free(home, search), search = NULL; if (domain) su_free(home, domain), domain = NULL; domain = su_strdup(home, value); if (!domain) return -1; } else if (MATCH("search")) { if (localdomain) /* LOCALDOMAIN overrides */ continue; if (search) su_free(home, search), search = NULL; if (domain) su_free(home, domain), domain = NULL; search = su_strdup(home, value); if (!search) return -1; } else if (MATCH("port")) { unsigned long port = strtoul(value, NULL, 10); if (port < 65536) c->c_port = port; } else if (MATCH("options")) { sres_parse_options(c, value); } } } if (f) c->c_modified = sres_config_timestamp(c); if (localdomain) c->c_search[0] = localdomain; else if (domain) c->c_search[0] = domain; else if (search) { for (i = 0; search[0] && i < SRES_MAX_SEARCH; i++) { c->c_search[i] = search; search += strcspn(search, " \t"); if (*search) { *search++ = '\0'; search += strspn(search, " \t"); } } } return i;}#if DOXYGEN_ONLY/**@ingroup sresolv_env * * Environment variable containing options for Sofia resolver. The options * recognized by Sofia resolver are as follows: * - @b debug turn on debugging (no effect) * - @b ndots:<i>n</i> when searching, try first to query name as absolute * domain if it contains at least <i>n</i> dots * - @b timeout:<i>secs</i> timeout in seconds * - @b attempts:<i>n</i> fail after <i>n</i> retries * - @b rotate use round robin selection of nameservers * - @b no-check-names do not check names for invalid characters * - @b inet6 (no effect) * - @b ip6-dotint IPv6 addresses are resolved using suffix ".ip6.int" * instead of the standard ".ip6.arpa" suffix * - @b ip6-bytestring (no effect) * The following option is a Sofia-specific extension: * - @b no-edns0 do not try to use EDNS0 extension (@RFC2671) * * The same options can be listed in @b options directive in resolv.conf, or * in #RES_OPTIONS environment variable. Note that options given in * #SRES_OPTIONS override those specified in #RES_OPTIONS which in turn * override options specified in the @b options directive of resolve.conf. * * The meaning of an option can be reversed with prefix "no-". * * @sa Manual page for resolv.conf, #RES_OPTIONS. */extern SRES_OPTIONS;/**@ingroup sresolv_env * * Environment variable containing resolver options. This environment * variable is also used by standard BIND resolver. * * @sa Manual page for resolv.conf, #SRES_OPTIONS. */extern RES_OPTIONS;/**@ingroup sresolv_env * * Environment variable containing search domain. This environment * variable is also used by standard BIND resolver. * * @sa Manual page for resolv.conf, #RES_OPTIONS, #SRES_OPTIONS. */extern LOCALDOMAIN;#endif/* Parse options line or #SRES_OPTIONS or #RES_OPTIONS environment variable. */static int sres_parse_options(sres_config_t *c, char const *value){ if (!value) return -1; while (value[0]) { char const *b; size_t len, extra = 0; unsigned long n = 0; b = value; len = strcspn(value, " \t:"); value += len; if (value[0] == ':') { len++; n = strtoul(++value, NULL, 10); value += extra = strcspn(value, " \t"); } if (*value) value += strspn(value, " \t"); if (n > 65536) { SU_DEBUG_3(("sres: %s: invalid %*.0s\n", c->c_filename, (int)(len + extra), b)); continue; } /* Documented by BIND9 resolv.conf */ if (MATCH("no-debug")) c->c_opt.debug = 0; else if (MATCH("debug")) c->c_opt.debug = 1; else if (MATCH("ndots:")) c->c_opt.ndots = n; else if (MATCH("timeout:")) c->c_opt.timeout = n; else if (MATCH("attempts:")) c->c_opt.attempts = n; else if (MATCH("no-rotate")) c->c_opt.rotate = 0; else if (MATCH("rotate")) c->c_opt.rotate = 1; else if (MATCH("no-check-names")) c->c_opt.check_names = 0; else if (MATCH("check-names")) c->c_opt.check_names = 1; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -