📄 sres.c
字号:
char const *domain){ if (socket == -1) return errno = EINVAL, NULL; return sres_query(res, callback, context, type, domain);}/** 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 sres_resolver_timer() is called in regular * intervals. It generates an error record with nonzero status if no * response is received. * * This function just makes sure that we have the @a socket is valid, * otherwise it behaves exactly like sres_query_sockaddr(). */sres_query_t *sres_query_make_sockaddr(sres_resolver_t *res, sres_answer_f *callback, sres_context_t *context, int socket, uint16_t type, struct sockaddr const *addr){ char name[80]; if (!res || !addr) return su_seterrno(EFAULT), (void *)NULL; if (socket == -1) return errno = EINVAL, NULL; if (!sres_sockaddr2string(res, name, sizeof(name), addr)) return NULL; return sres_query_make(res, callback, context, socket, 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", 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 **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. * * * * @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;}/** 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; for (n = 0, i = 0; answers && answers[i]; i++) { if (answers[i]->sr_record->r_status || answers[i]->sr_record->r_class != sres_class_in || (type != 0 && answers[i]->sr_record->r_type != type)) { sres_free_answer(res, answers[i]); continue; } answers[n++] = answers[i]; } answers[n] = NULL; sres_sort_answers(res, answers); return n;}/** Free and zero one record. */void sres_free_answer(sres_resolver_t *res, sres_record_t *answer){ if (res && answer) sres_cache_free_one(res->res_cache, answer);}/** Free and zero an array of records. * * The array of records can be returned by sres_cached_answers() or * given by callback function. */void sres_free_answers(sres_resolver_t *res, sres_record_t **answers){ if (res && answers) sres_cache_free_answers(res->res_cache, answers);}/** Convert type to its name. */char const *sres_record_type(int type, char buffer[8]){ switch (type) { case sres_type_a: return "A"; case sres_type_ns: return "NS"; case sres_type_mf: return "MF"; case sres_type_cname: return "CNAME"; case sres_type_soa: return "SOA"; case sres_type_mb: return "MB"; case sres_type_mg: return "MG"; case sres_type_mr: return "MR"; case sres_type_null: return "NULL"; case sres_type_wks: return "WKS"; case sres_type_ptr: return "PTR"; case sres_type_hinfo: return "HINFO"; case sres_type_minfo: return "MINFO"; case sres_type_mx: return "MX"; case sres_type_txt: return "TXT"; case sres_type_rp: return "RP"; case sres_type_afsdb: return "AFSDB"; case sres_type_x25: return "X25"; case sres_type_isdn: return "ISDN"; case sres_type_rt: return "RT"; case sres_type_nsap: return "NSAP"; case sres_type_nsap_ptr: return "NSAP_PTR"; case sres_type_sig: return "SIG"; case sres_type_key: return "KEY"; case sres_type_px: return "PX"; case sres_type_gpos: return "GPOS"; case sres_type_aaaa: return "AAAA"; case sres_type_loc: return "LOC"; case sres_type_nxt: return "NXT"; case sres_type_eid: return "EID"; case sres_type_nimloc: return "NIMLOC"; case sres_type_srv: return "SRV"; case sres_type_atma: return "ATMA"; case sres_type_naptr: return "NAPTR"; case sres_type_kx: return "KX"; case sres_type_cert: return "CERT"; case sres_type_a6: return "A6"; case sres_type_dname: return "DNAME"; case sres_type_sink: return "SINK"; case sres_type_opt: return "OPT"; case sres_qtype_tsig: return "TSIG"; case sres_qtype_ixfr: return "IXFR"; case sres_qtype_axfr: return "AXFR"; case sres_qtype_mailb: return "MAILB"; case sres_qtype_maila: return "MAILA"; case sres_qtype_any: return "ANY"; default: sprintf(buffer, "%u?", type & 65535); return buffer; }}/** Convert class to its name. */char const *sres_record_class(int rclass, char buffer[8]){ switch (rclass) { case 1: return "IN"; case 2: return "2?"; case 3: return "CHAOS"; case 4: return "HS"; case 254: return "NONE"; case 255: return "ANY"; default: sprintf(buffer, "%u?", rclass & 65535); return buffer; }}/** Compare two records. */int sres_record_compare(sres_record_t const *aa, sres_record_t const *bb){ int D; sres_common_t const *a = aa->sr_record, *b = bb->sr_record; D = a->r_status - b->r_status; if (D) return D; D = a->r_class - b->r_class; if (D) return D; D = a->r_type - b->r_type; if (D) return D; if (a->r_status) return 0; switch (a->r_type) { case sres_type_soa: { sres_soa_record_t const *A = aa->sr_soa, *B = bb->sr_soa; D = A->soa_serial - B->soa_serial; if (D) return D; D = strcasecmp(A->soa_mname, B->soa_mname); if (D) return D; D = strcasecmp(A->soa_rname, B->soa_rname); if (D) return D; D = A->soa_refresh - B->soa_refresh; if (D) return D; D = A->soa_retry - B->soa_retry; if (D) return D; D = A->soa_expire - B->soa_expire; if (D) return D; D = A->soa_minimum - B->soa_minimum; if (D) return D; return 0; } case sres_type_a: { sres_a_record_t const *A = aa->sr_a, *B = bb->sr_a; return memcmp(&A->a_addr, &B->a_addr, sizeof A->a_addr); } case sres_type_a6: { sres_a6_record_t const *A = aa->sr_a6, *B = bb->sr_a6; D = A->a6_prelen - B->a6_prelen; if (D) return D; D = !A->a6_prename - !B->a6_prename; if (D == 0 && A->a6_prename && B->a6_prename) D = strcasecmp(A->a6_prename, B->a6_prename); if (D) return D; return memcmp(&A->a6_suffix, &B->a6_suffix, sizeof A->a6_suffix); } case sres_type_aaaa: { sres_aaaa_record_t const *A = aa->sr_aaaa, *B = bb->sr_aaaa; return memcmp(&A->aaaa_addr, &B->aaaa_addr, sizeof A->aaaa_addr); } case sres_type_cname: { sres_cname_record_t const *A = aa->sr_cname, *B = bb->sr_cname; return strcmp(A->cn_cname, B->cn_cname); } case sres_type_ptr: { sres_ptr_record_t const *A = aa->sr_ptr, *B = bb->sr_ptr; return strcmp(A->ptr_domain, B->ptr_domain); } case sres_type_srv: { sres_srv_record_t const *A = aa->sr_srv, *B = bb->sr_srv; D = A->srv_priority - B->srv_priority; if (D) return D; /* Record with larger weight first */ D = B->srv_weight - A->srv_weight; if (D) return D; D = strcmp(A->srv_target, B->srv_target); if (D) return D; return A->srv_port - B->srv_port; } case sres_type_naptr: { sres_naptr_record_t const *A = aa->sr_naptr, *B = bb->sr_naptr; D = A->na_order - B->na_order; if (D) return D; D = A->na_prefer - B->na_prefer; if (D) return D; D = strcmp(A->na_flags, B->na_flags); if (D) return D; D = strcmp(A->na_services, B->na_services); if (D) return D; D = strcmp(A->na_regexp, B->na_regexp); if (D) return D; return strcmp(A->na_replace, B->na_replace); } default: return 0; }}/* ---------------------------------------------------------------------- *//* Private functions */static void sres_resolver_destructor(void *arg){ sres_resolver_t *res = arg; assert(res); sres_cache_unref(res->res_cache); res->res_cache = NULL; sres_servers_unref(res, res->res_servers); if (res->res_updcb) res->res_updcb(res->res_async, -1, -1);}/* * 3571 is a prime => * we hash successive id values to different parts of hash tables */#define Q_PRIME 3571#define SRES_QUERY_HASH(q) ((q)->q_hash)HTABLE_BODIES(sres_qtable, qt, sres_query_t, SRES_QUERY_HASH);/** Allocate a query structure */staticsres_query_t *sres_query_alloc(sres_resolver_t *res, sres_answer_f *callback, sres_context_t *context, uint16_t type, char const *domain){ sres_query_t *query; size_t dlen = strlen(domain); if (sres_qtable_is_full(res->res_queries)) if (sres_qtable_resize(res->res_home, res->res_queries, 0) < 0) return NULL; query = su_alloc(res->res_home, sizeof(*query) + dlen + 1); if (query) { memset(query, 0, sizeof *query); query->q_res = res; query->q_callback = callback; query->q_context = context; query->q_type = type; query->q_class = sres_class_in; query->q_timestamp = res->res_now; query->q_name = strcpy((char *)(query + 1), domain); query->q_id = sres_new_id(res); assert(query->q_id); query->q_i_server = res->res_i_server; query->q_n_servers = res->res_n_servers;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -