📄 sres.c
字号:
query->q_hash = query->q_id * Q_PRIME /* + query->q_i_server */; sres_qtable_append(res->res_queries, query); } return query;}static inlinevoid sres_remove_query(sres_resolver_t *res, sres_query_t *q, int all){ int i; if (q->q_hash) { sres_qtable_remove(res->res_queries, q), q->q_hash = 0; if (all) for (i = 0; i <= SRES_MAX_SEARCH; i++) { if (q->q_subqueries[i] && q->q_subqueries[i]->q_hash) { sres_qtable_remove(res->res_queries, q->q_subqueries[i]); q->q_subqueries[i]->q_hash = 0; } } }}/** Remove a query from hash table and free it. */staticvoid sres_free_query(sres_resolver_t *res, sres_query_t *q){ int i; if (q == NULL) return; if (q->q_hash) sres_qtable_remove(res->res_queries, q), q->q_hash = 0; for (i = 0; i <= SRES_MAX_SEARCH; i++) { sres_query_t *sq; sq = q->q_subqueries[i]; q->q_subqueries[i] = NULL; if (sq) sres_free_query(res, sq); if (q->q_subanswers[i]) sres_cache_free_answers(res->res_cache, q->q_subanswers[i]); q->q_subanswers[i] = NULL; } su_free(res->res_home, q);}staticsres_record_t **sres_combine_results(sres_resolver_t *res, sres_record_t **search_results[SRES_MAX_SEARCH + 1]){ sres_record_t **combined_result; int i, j, found; /* Combine the results into a single list. */ for (i = 0, found = 0; i <= SRES_MAX_SEARCH; i++) if (search_results[i]) for (j = 0; search_results[i][j]; j++) found++; combined_result = su_alloc((su_home_t *)res->res_cache, (found + 1) * (sizeof combined_result[0])); if (combined_result) { for (i = 0, found = 0; i <= SRES_MAX_SEARCH; i++) if (search_results[i]) for (j = 0; search_results[i][j]; j++) { combined_result[found++] = search_results[i][j]; search_results[i][j] = NULL; } combined_result[found] = NULL; sres_sort_answers(res, combined_result); } for (i = 0; i <= SRES_MAX_SEARCH; i++) if (search_results[i]) sres_free_answers(res, search_results[i]), search_results[i] = NULL; return combined_result;}staticintsres_sockaddr2string(sres_resolver_t *res, char name[], size_t namelen, struct sockaddr const *addr){ name[0] = '\0'; if (addr->sa_family == AF_INET) { struct sockaddr_in const *sin = (struct sockaddr_in *)addr; uint8_t const *in_addr = (uint8_t*)&sin->sin_addr; return snprintf(name, namelen, "%u.%u.%u.%u.in-addr.arpa.", in_addr[3], in_addr[2], in_addr[1], in_addr[0]); }#if HAVE_SIN6 else if (addr->sa_family == AF_INET6) { struct sockaddr_in6 const *sin6 = (struct sockaddr_in6 *)addr; int addrsize = sizeof(sin6->sin6_addr.s6_addr); char *postfix; int required; int i; if (res->res_config->c_opt.ip6int) postfix = "ip6.int."; else postfix = "ip6.arpa."; required = addrsize * 4 + strlen(postfix); if (namelen <= required) return required; for (i = 0; i < addrsize; i++) { uint8_t byte = sin6->sin6_addr.s6_addr[addrsize - i - 1]; uint8_t hex; hex = byte & 0xf; name[4 * i] = hex > 9 ? hex + 'a' - 10 : hex + '0'; name[4 * i + 1] = '.'; hex = (byte >> 4) & 0xf; name[4 * i + 2] = hex > 9 ? hex + 'a' - 10 : hex + '0'; name[4 * i + 3] = '.'; } strcpy(name + 4 * i, postfix); return required; }#endif else { su_seterrno(EAFNOSUPPORT); SU_DEBUG_3(("%s: %s\n", "sres_sockaddr2string", su_strerror(EAFNOSUPPORT))); return 0; }}/** Make a domain name a top level domain name. * * The function sres_toplevel() returns a copies string @a domain and * terminates it with a dot if it is not already terminated. */staticchar const *sres_toplevel(char buf[], size_t blen, char const *domain){ size_t len; int already; if (!domain) return su_seterrno(EFAULT), (void *)NULL; len = strlen(domain); if (len >= blen) return su_seterrno(ENAMETOOLONG), (void *)NULL; already = len > 0 && domain[len - 1] == '.'; if (already) return domain; if (len + 1 >= blen) return su_seterrno(ENAMETOOLONG), (void *)NULL; strcpy(buf, domain); buf[len] = '.'; buf[len + 1] = '\0'; return buf;}/* ---------------------------------------------------------------------- */static int sres_parse_config(sres_config_t *, FILE *);static int sres_parse_options(sres_config_t *c, char const *value);static int sres_parse_nameserver(sres_config_t *c, char const *server);static time_t sres_config_timestamp(sres_config_t const *c);/** Update configuration * */int sres_resolver_update(sres_resolver_t *res, int always){ sres_config_t *c = NULL; sres_config_t const *previous; sres_server_t **servers, **old_servers; previous = res->res_config; time(&res->res_now); if (!always && previous && res->res_now < res->res_checked) return 0; /* Try avoid checking for changes too often. */ res->res_checked = res->res_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; if (sres_config_changed_servers(c, previous)) { servers = sres_servers_new(res, c); if (!servers) { su_home_unref((void *)c->c_home); return -1; } old_servers = res->res_servers; res->res_i_server = 0; res->res_n_servers = sres_servers_count(servers); res->res_servers = servers; sres_servers_unref(res, old_servers); } su_home_unref((su_home_t *)previous->c_home); return 0;}#if _WIN32/** Number of octets to read from a registry key at a time */#define QUERY_DATALEN 1024#define MAX_DATALEN 65535/** * 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; char *name_servers = su_alloc(home, QUERY_DATALEN); int 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 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, 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;}#endif /* _WIN32 *//** * 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/ */static int sres_parse_win32_reg(sres_config_t *c){ int ret = -1;#ifdef _WIN32#define MAX_KEY_LEN 255#define MAX_VALUE_NAME_LEN 16383 su_home_t *home = c->c_home; HKEY key_handle, interface_key_handle; FILETIME ftime; int index, i, found = 0; char *interface_guid = su_alloc(home, MAX_VALUE_NAME_LEN); int guid_size = MAX_VALUE_NAME_LEN; /* step 1: find interface specific nameservers */ /* 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); } /* step 2: 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);#endif /* _WIN32 */ return ret;}/** 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_clone(res->res_home, (sizeof *c)); if (c) { FILE *f; int i, success = 0; f = fopen(c->c_filename = res->res_cnffile, "r"); sres_parse_config(c, f); if (f) fclose(f); /* on win32, query the registry for nameservers */ if (sres_parse_win32_reg(c) == 0) ++success;#ifndef _WIN32 /* note: no 127.0.0.1 on win32 systems */ 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;}/** 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 = 53; if (f != NULL) { for (line = 1; fgets(buf, sizeof(buf), f); line++) { int 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -