📄 sres.c
字号:
return su_seterrno(EFAULT); for (n = 0, i = 0; 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 *//** Destruct */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_close(res, res->res_servers); if (res->res_config) su_home_unref((su_home_t *)res->res_config->c_home); if (res->res_updcb) res->res_updcb(res->res_async, INVALID_SOCKET, INVALID_SOCKET);}/* * 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_WITH(sres_qtable, qt, sres_query_t, SRES_QUERY_HASH, unsigned, size_t);/** 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; query->q_hash = query->q_id * Q_PRIME /* + query->q_i_server */; sres_qtable_append(res->res_queries, query); if (res->res_schedulecb && res->res_queries->qt_used == 1) res->res_schedulecb(res->res_async, 2 * SRES_RETRANSMIT_INTERVAL); } return query;}su_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; size_t addrsize = sizeof(sin6->sin6_addr.s6_addr); char *postfix; size_t required; size_t i; if (res->res_config->c_opt.ip6int) postfix = "ip6.int."; else postfix = "ip6.arpa."; required = addrsize * 4 + strlen(postfix); if (namelen <= required) return (int)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 (int)required; }#endif /* HAVE_SIN6 */ 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_update_config(sres_resolver_t *res, int always, time_t now);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 * * @retval 0 when successful * @retval -1 upon an error */int sres_resolver_update(sres_resolver_t *res, int always){ sres_server_t **servers, **old_servers; int updated; updated = sres_update_config(res, always, time(&res->res_now)); if (updated < 0) return -1; if (!res->res_servers || always || updated) { servers = sres_servers_new(res, res->res_config); old_servers = res->res_servers; res->res_i_server = 0; res->res_n_servers = sres_servers_count(servers); res->res_servers = servers; sres_servers_close(res, old_servers); su_free(res->res_home, old_servers); if (!servers) return -1; } return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -