📄 sres.c
字号:
return (void)su_seterrno(ENETDOWN), (sres_query_t *)NULL; query = sres_query_alloc(res, callback, context, type, domain); if (query && sres_send_dns_query(res, query) != 0) sres_free_query(res, query), query = NULL; return query;}/**Search DNS. * * Sends DNS queries with specified @a type and @a name to the DNS server. * If the @a name does not contain enought dots, the search domains are * appended to the name and resulting domain name are also queried. When * answer to all the search domains is received, the @a callback function * is called with @a context and combined records from answers as arguments. * * The sres resolver takes care of retransmitting the queries if a root * object is associate with the resolver or if sres_resolver_timer() is * called in regular intervals. It generates an error record with nonzero * status if no response is received. * * @param res pointer to resolver object * @param callback pointer to completion function * @param context argument given to the completion function * @param type record type to search (or sres_qtype_any for any record) * @param name host or domain name to search from DNS * * @ERRORS * @ERROR EFAULT @a res or @a domain point outside the address space * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME * @ERROR ENETDOWN no DNS servers configured * @ERROR ENOMEM memory exhausted * * @sa sres_query(), sres_blocking_search(), sres_search_cached_answers(). */sres_query_t *sres_search(sres_resolver_t *res, sres_answer_f *callback, sres_context_t *context, uint16_t type, char const *name){ char const *domain = name; sres_query_t *query = NULL; size_t dlen; unsigned dots; char const *dot; char b[8]; SU_DEBUG_9(("sres_search(%p, %p, %s, \"%s\") called\n", (void *)res, (void *)context, sres_record_type(type, b), domain)); if (res == NULL || domain == NULL) return su_seterrno(EFAULT), (void *)NULL; dlen = strlen(domain); if (dlen > SRES_MAXDNAME || (dlen == SRES_MAXDNAME && domain[dlen - 1] != '.')) { su_seterrno(ENAMETOOLONG); return NULL; } sres_resolver_update(res, 0); if (res->res_n_servers == 0) return (void)su_seterrno(ENETDOWN), (sres_query_t *)NULL; if (domain[dlen - 1] == '.') /* Domain ends with dot - do not search */ dots = res->res_config->c_opt.ndots; else if (sres_has_search_domain(res)) for (dots = 0, dot = strchr(domain, '.'); dots < res->res_config->c_opt.ndots && dot; dots++, dot = strchr(dot + 1, '.')) ; else dots = 0; query = sres_query_alloc(res, callback, context, type, domain); if (query) { /* Create sub-query for each search domain */ if (dots < res->res_config->c_opt.ndots) { sres_query_t *sub; int i, subs; size_t len; char const *const *domains = res->res_config->c_search; char search[SRES_MAXDNAME + 1]; assert(dlen < SRES_MAXDNAME); memcpy(search, domain, dlen); search[dlen++] = '.'; search[dlen] = '\0'; for (i = 0, subs = 0; i <= SRES_MAX_SEARCH; i++) { if (domains[i]) { len = strlen(domains[i]); if (dlen + len + 1 > SRES_MAXDNAME) continue; memcpy(search + dlen, domains[i], len); search[dlen + len] = '.'; search[dlen + len + 1] = '\0'; sub = sres_query_alloc(res, sres_answer_subquery, (void *)query, type, search); if (sub == NULL) { } else if (sres_send_dns_query(res, sub) == 0) { query->q_subqueries[i] = sub; } else { sres_free_query(res, sub), sub = NULL; } subs += sub != NULL; } } query->q_n_subs = subs; } if (sres_send_dns_query(res, query) != 0) { if (!query->q_n_subs) sres_free_query(res, query), query = NULL; else query->q_id = 0; } } return query;}/** Make a reverse DNS query. * * Send a query to DNS server with specified @a type and domain name formed * from the socket address @a addr. The sres resolver takes care of * retransmitting the query if a root object is associate with the resolver or * if sres_resolver_timer() is called in regular intervals. It generates an * error record with nonzero status if no response is received. * * @param res pointer to resolver * @param callback function called when query is answered or times out * @param context pointer given as an extra argument to @a callback function * @param type record type to query (or sres_qtype_any for any record) * @param addr socket address structure * * The @a type should be #sres_type_ptr. The @a addr should contain either * IPv4 (AF_INET) or IPv6 (AF_INET6) address. * * If the #SRES_OPTIONS environment variable, #RES_OPTIONS environment * variable, or an "options" entry in resolv.conf file contains an option * "ip6-dotint", the IPv6 addresses are resolved using suffix ".ip6.int" * instead of the standard ".ip6.arpa" suffix. * * @ERRORS * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported * @ERROR ENETDOWN no DNS servers configured * @ERROR EFAULT @a res or @a addr point outside the address space * @ERROR ENOMEM memory exhausted * * @sa sres_query(), sres_blocking_query_sockaddr(), * sres_cached_answers_sockaddr() * */sres_query_t *sres_query_sockaddr(sres_resolver_t *res, sres_answer_f *callback, sres_context_t *context, uint16_t type, struct sockaddr const *addr){ char name[80]; if (!res || !addr) return su_seterrno(EFAULT), (void *)NULL; if (!sres_sockaddr2string(res, name, sizeof(name), addr)) return NULL; return sres_query(res, callback, context, type, name);}/** Make a DNS query. * * @deprecated Use sres_query() instead. */sres_query_t *sres_query_make(sres_resolver_t *res, sres_answer_f *callback, sres_context_t *context, int dummy, uint16_t type, char const *domain){ return sres_query(res, callback, context, type, domain);}/** Make a reverse DNS query. * * @deprecated Use sres_query_sockaddr() instead. */sres_query_t *sres_query_make_sockaddr(sres_resolver_t *res, sres_answer_f *callback, sres_context_t *context, int dummy, uint16_t type, struct sockaddr const *addr){ char name[80]; if (!res || !addr) return su_seterrno(EFAULT), (void *)NULL; if (!sres_sockaddr2string(res, name, sizeof(name), addr)) return NULL; return sres_query_make(res, callback, context, dummy, type, name);}/** Bind a query with another callback and context pointer. * * @param query pointer to a query object to bind * @param callback pointer to new callback function (may be NULL) * @param context pointer to callback context (may be NULL)*/void sres_query_bind(sres_query_t *query, sres_answer_f *callback, sres_context_t *context){ if (query) { query->q_callback = callback; query->q_context = context; }}/**Get a list of matching (type/domain) records from cache. * * @return * pointer to an array of pointers to cached records, or * NULL if no entry was found. * * @ERRORS * @ERROR ENAMETOOLONG @a domain is longer than SRES_MAXDNAME * @ERROR ENOENT no cached records were found * @ERROR EFAULT @a res or @a domain point outside the address space * @ERROR ENOMEM memory exhausted */sres_record_t **sres_cached_answers(sres_resolver_t *res, uint16_t type, char const *domain){ sres_record_t **result; char rooted_domain[SRES_MAXDNAME]; if (!res) return su_seterrno(EFAULT), (void *)NULL; domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain); if (!domain) return NULL; if (!sres_cache_get(res->res_cache, type, domain, &result)) return su_seterrno(ENOENT), (void *)NULL; return result;}/**Search for a list of matching (type/name) records from cache. * * @return * pointer to an array of pointers to cached records, or * NULL if no entry was found. * * @ERRORS * @ERROR ENAMETOOLONG @a name or resulting domain is longer than SRES_MAXDNAME * @ERROR ENOENT no cached records were found * @ERROR EFAULT @a res or @a domain point outside the address space * @ERROR ENOMEM memory exhausted * * @sa sres_search(), sres_cached_answers() */sres_record_t **sres_search_cached_answers(sres_resolver_t *res, uint16_t type, char const *name){ char const *domain = name; sres_record_t **search_results[SRES_MAX_SEARCH + 1] = { NULL }; char rooted_domain[SRES_MAXDNAME]; unsigned dots; char const *dot; size_t found = 0; int i; SU_DEBUG_9(("sres_search_cached_answers(%p, %s, \"%s\") called\n", (void *)res, sres_record_type(type, rooted_domain), domain)); if (!res || !name) return su_seterrno(EFAULT), (void *)NULL; if (sres_has_search_domain(res)) for (dots = 0, dot = strchr(domain, '.'); dots < res->res_config->c_opt.ndots && dot; dots++, dot = strchr(dot + 1, '.')) ; else dots = 0; domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain); if (!domain) return NULL; if (sres_cache_get(res->res_cache, type, domain, &search_results[0])) found = 1; if (dots < res->res_config->c_opt.ndots) { char const *const *domains = res->res_config->c_search; size_t dlen = strlen(domain); for (i = 0; domains[i] && i < SRES_MAX_SEARCH; i++) { size_t len = strlen(domains[i]); if (dlen + len + 1 >= SRES_MAXDNAME) continue; if (domain != rooted_domain) domain = memcpy(rooted_domain, domain, dlen); memcpy(rooted_domain + dlen, domains[i], len); strcpy(rooted_domain + dlen + len, "."); if (sres_cache_get(res->res_cache, type, domain, search_results + i + 1)) found++; } } if (found == 0) return su_seterrno(ENOENT), (void *)NULL; if (found == 1) { for (i = 0; i <= SRES_MAX_SEARCH; i++) if (search_results[i]) return search_results[i]; } return sres_combine_results(res, search_results);}/**Get a list of matching (type/domain) reverse records from cache. * * @param res pointer to resolver * @param type record type to query (or sres_qtype_any for any record) * @param addr socket address structure * * The @a type should be #sres_type_ptr. The @a addr should contain either * IPv4 (AF_INET) or IPv6 (AF_INET6) address. * * If the #SRES_OPTIONS environment variable, #RES_OPTIONS environment * variable or an "options" entry in resolv.conf file contains an option * "ip6-dotint", the IPv6 addresses are resolved using suffix ".ip6.int" * instead of default ".ip6.arpa". * * @retval * pointer to an array of pointers to cached records, or * NULL if no entry was found. * * @ERRORS * @ERROR EAFNOSUPPORT address family specified in @a addr is not supported * @ERROR ENOENT no cached records were found * @ERROR EFAULT @a res or @a addr point outside the address space * @ERROR ENOMEM memory exhausted */sres_record_t **sres_cached_answers_sockaddr(sres_resolver_t *res, uint16_t type, struct sockaddr const *addr){ sres_record_t **result; char name[80]; if (!res || !addr) return su_seterrno(EFAULT), (void *)NULL; if (!sres_sockaddr2string(res, name, sizeof name, addr)) return NULL; if (!sres_cache_get(res->res_cache, type, name, &result)) su_seterrno(ENOENT), (void *)NULL; return result;}/** Set the priority of the matching cached SRV record. * * The SRV records with the domain name, target and port are matched and * their priority value is adjusted. This function is used to implement * greylisting of SIP servers. * * @param res pointer to resolver * @param domain domain name of the SRV record(s) to modify * @param target SRV target of the SRV record(s) to modify * @param port port number of SRV record(s) to modify * (in host byte order) * @param ttl new ttl for SRV records of the domain * @param priority new priority value (0=highest, 65535=lowest) * * @sa sres_cache_set_srv_priority() * * @NEW_1_12_8 */int sres_set_cached_srv_priority(sres_resolver_t *res, char const *domain, char const *target, uint16_t port, uint32_t ttl, uint16_t priority){ char rooted_domain[SRES_MAXDNAME]; if (res == NULL || res->res_cache == NULL) return su_seterrno(EFAULT); domain = sres_toplevel(rooted_domain, sizeof rooted_domain, domain); if (!domain) return -1; return sres_cache_set_srv_priority(res->res_cache, domain, target, port, ttl, priority);}/** Sort answers. */intsres_sort_answers(sres_resolver_t *res, sres_record_t **answers){ int i, j; if (res == NULL || answers == NULL) return su_seterrno(EFAULT); if (answers[0] == NULL || answers[1] == NULL) return 0; /* Simple insertion sorting */ /* * We do not use qsort because we want later extend this to sort * local A records first etc. */ for (i = 1; answers[i]; i++) { for (j = 0; j < i; j++) { if (sres_record_compare(answers[i], answers[j]) < 0) break; } if (j < i) { sres_record_t *r = answers[i]; for (; j < i; i--) { answers[i] = answers[i - 1]; } answers[j] = r; } } return 0;}/** Sort and filter query results */intsres_filter_answers(sres_resolver_t *res, sres_record_t **answers, uint16_t type){ int i, n; if (res == NULL || answers == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -