⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sresolv.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
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);    }#if SU_HAVE_IN6  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);          }#endif  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;  }}static intsres_sockaddr2string(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);    int required = addrsize * 4 + strlen("ip6.int.");    int i;    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, "ip6.int");    return required;  }#endif  else {    su_seterrno(EAFNOSUPPORT);    SU_DEBUG_3(("%s: %s\n", "sres_sockaddr2string",                 su_strerror(EAFNOSUPPORT)));    return 0;  }}/** Parse /etc/resolv.conf file. * * @retval 0 when successful  * @retval -1 upon an error * * @todo The resolv.conf directives @b sortlist and options  *       are currently ignored. */static intsres_parse_resolv_conf(sres_resolver_t *res, const char *filename){  char buf[PATH_MAX];  FILE *f;  int line;  su_home_t *home = res->res_home;  su_strlst_t *dns_list;  sres_server_t *dns;  int num_servers, i, search = 0;  char const *localdomain = getenv("LOCALDOMAIN");  res->res_search[0] = localdomain;  dns_list = su_strlst_create(home);  if (filename)    res->res_config = su_strdup(res->res_home, filename);  else    res->res_config = filename = "/etc/resolv.conf";  f = fopen(filename, "r");  if (f != NULL) {      for (line = 1; fgets(buf, sizeof(buf), f); line++) {      int n;      char *value, *b;      /* Skip whitespace at the beginning ...*/      b = buf + strspn(buf, " \t");      /* ... and at the end of line */      for (n = strlen(b); n > 0 && strchr(" \t\r\n", b[n - 1]); n--)	;      if (n == 0 || b[0] == '#') 	/* Empty line or comment */	continue;      b[n] = '\0';      n = strcspn(b, " \t");      value = b + n; value += strspn(value, " \t");#define MATCH(token) (n == strlen(token) && strncasecmp(token, b, n) == 0)      if (MATCH("nameserver")) {	su_strlst_dup_append(dns_list, value);      }      else if (MATCH("domain")) {	if (localdomain)	  continue;	memset(res->res_search, 0, sizeof res->res_search);	res->res_search[0] = su_strdup(home, value);      }      else if (MATCH("search")) {	if (localdomain)	  continue;	memset(res->res_search, 0, sizeof res->res_search);	while (value[0] && search < SRES_MAX_SEARCH) {	  n = strcspn(value, " \t\r\n");	  res->res_search[search++ + 1] = su_strndup(home, value, n);	  value += n + strspn(value + n, " \t\r\n");	}      }      else if (MATCH("port")) {	unsigned long port = strtoul(value, NULL, 10);	res->res_port = port;      }    }    fclose(f);  }    num_servers = su_strlst_len(dns_list);  if (num_servers == 0) {    su_strlst_dup_append(dns_list, "127.0.0.1");    num_servers++;  }  res->res_n_servers = num_servers;  dns = su_zalloc(res->res_home, num_servers * sizeof(*res->res_servers));  res->res_servers = dns;  if (!dns)    return -1;  for (i = 0; i < num_servers; i++) {    const char* server = su_strlst_item(dns_list, i);    struct sockaddr *sa = (struct sockaddr *)dns->dns_addr;    int err;#if HAVE_SIN6 && 0		/* Disabled for now */    if (strchr(server, ':')) {      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;      memset(sa, 0, dns->dns_addrlen = sizeof *sin6);      err = inet_pton(sa->sa_family = AF_INET6, server, &sin6->sin6_addr);      sin6->sin6_port = htons(res->res_port);    }     else #endif      {      struct sockaddr_in *sin = (struct sockaddr_in *)sa;      memset(sa, 0, dns->dns_addrlen = sizeof *sin);      err = inet_pton(sa->sa_family = AF_INET, server, &sin->sin_addr);      sin->sin_port = htons(res->res_port);    }    if (err <= 0) {      res->res_n_servers--;      SU_DEBUG_3(("sres: nameserver %s: invalid address\n", server));      continue;    }#if HAVE_SA_LEN    sa->sa_len = dns->dns_addrlen;#endif    dns->dns_name = su_strdup(res->res_home, server);    dns->dns_edns = 1;    dns++;  }  su_strlst_destroy(dns_list);  return res->res_n_servers;}/** Send a query packet */static int sres_send_dns_query(sres_resolver_t *res, 		    sres_query_t *q){                          sres_message_t m[1];  int i, i0, N = res->res_n_servers;  int transient, error;  unsigned size, no_edns_size, edns_size;  uint16_t id = q->q_id;  uint16_t type = q->q_type;  char const *domain = q->q_name;  sres_server_t *dns;  SU_DEBUG_9(("sres_send_dns_query(%p, %p) called\n", res, q));  if (domain == NULL)    return -1;  memset(m, 0, offsetof(sres_message_t, m_data[sizeof m->m_packet.mp_header]));  /* Create a DNS message */  m->m_size = sizeof(m->m_data);  m->m_offset = size = sizeof(m->m_packet.mp_header);    m->m_id = id;  m->m_flags = htons(SRES_HDR_QUERY | SRES_HDR_RD);    /* Query record */  m->m_qdcount = htons(1);  m_put_domain(m, domain, 0, NULL);  m_put_uint16(m, type);  m_put_uint16(m, sres_class_in);    no_edns_size = m->m_offset;  /* EDNS0 record (optional) */  m_put_domain(m, ".", 0, NULL);  m_put_uint16(m, sres_type_opt);  m_put_uint16(m, sizeof(m->m_packet)); /* Class: our UDP payload size */  m_put_uint32(m, 0);		/* TTL: extended RCODE & flags */  m_put_uint16(m, 0);    edns_size = m->m_offset;  if (m->m_error) {    SU_DEBUG_3(("%s(): encoding: %s\n", "sres_send_dns_query", m->m_error));    su_seterrno(EIO);    return -1;  }  i = i0 = q->q_i_server; assert(i0 < N);  transient = 0;  for (;;) {    dns = res->res_servers + i;    /* If server supports EDNS, include EDNS0 record */    q->q_edns = dns->dns_edns != 0;    /* 0 (no EDNS) or 1 (EDNS supported) additional data records */    m->m_arcount = htons(q->q_edns);     /* Size with or without EDNS record */    size = q->q_edns ? edns_size : no_edns_size;     /* Send the DNS message to the UDP socket */    if (sendto(q->q_socket, m->m_data, size, 0,	       (struct sockaddr *)dns->dns_addr, dns->dns_addrlen) == size)      break;    error = su_errno();    /* EINVAL is returned if destination address is bad */    if (transient++ < 3 && error != EINVAL)      continue;    transient = 0;    dns->dns_icmp_error = res->res_now;	/* Mark as a bad destination */    /* Retry using another server */    for (i = (i + 1) % N; res->res_servers[i].dns_icmp_error; i = (i + 1) % N) {      if (i == i0) {	/* All servers have reported errors */	SU_DEBUG_5(("%s(): sendto: %s\n", "sres_send_dns_query",		    su_strerror(error)));	return su_seterrno(error);      }    }  }  q->q_i_server = i;  SU_DEBUG_5(("%s(%p, %p) id=%u %u? %s (to [%s]:%u)\n", "sres_send_dns_query",	      res, q, id, type, domain, dns->dns_name, res->res_port));  return 0;}/** * Callback function for subqueries */staticvoid sres_answer_subquery(sres_context_t *context, 			  sres_query_t *query,			  sres_record_t **answers){  sres_resolver_t *res;  sres_query_t *top = (sres_query_t *)context;  int i;  assert(top); assert(top->q_n_subs > 0); assert(query);  res = query->q_res;  LOCK(query->q_res);  for (i = 0; i <= SRES_MAX_SEARCH; i++) {    if (top->q_subqueries[i] == query)      break;  }  assert(i <= SRES_MAX_SEARCH);  if (i > SRES_MAX_SEARCH || top->q_n_subs == 0) {    _sres_free_answers(res, answers);    UNLOCK(res);    return;  }  if (answers) {    int j, k;    for (j = 0, k = 0; answers[j]; j++) {      if (answers[j]->sr_status)	_sres_free_answer(query->q_res, answers[j]);      else	answers[k++] = answers[j];    }    answers[k] = NULL;    if (!answers[0])      _sres_free_answers(query->q_res, answers), answers = NULL;  }  top->q_subqueries[i] = NULL;  top->q_subanswers[i] = answers;  if (--top->q_n_subs == 0 && top->q_id == 0) {    sres_query_report_error(top->q_res, top, NULL);  };  UNLOCK(res);}/** Report sres error */static voidsres_query_report_error(sres_resolver_t *res, sres_query_t *q,			sres_record_t **answers){  int i;  if (q->q_callback) {    for (i = 0; i <= SRES_MAX_SEARCH; i++) {      if (q->q_subqueries[i])	/* a pending query... */	return;      if (q->q_subanswers[i]) {	answers = q->q_subanswers[i];	q->q_subanswers[i] = NULL;	break;      }    }    SU_DEBUG_5(("sres(%p): reporting errors for %u %s\n",		res, q->q_type, q->q_name));     sres_remove_query(res, q, 1);    UNLOCK(res);    (q->q_callback)(q->q_context, q, answers);    LOCK(res);  }  sres_free_query(res, q);}/** Resolver timer function. * * The function sresolver_timer() should be called in regular intervals. We * recommend calling it in 500 ms intervals. * */void sres_resolver_timer(sres_resolver_t *res, int socket){  int i;  sres_query_t *q;  time_t now, retry_time;  if (res == NULL)    return;  if (!LOCK(res))    return;  now = time(&res->res_now);  if (res->res_queries->qt_used) {    /** Every time it is called it goes through all query structures, and     * retransmits all the query messages, which have not been answered yet.     */    for (i = 0; i < res->res_queries->qt_size; i++) {      q = res->res_queries->qt_table[i];            if (!q || q->q_socket != socket)	continue;            /* Exponential backoff */      retry_time = q->q_timestamp + (1 << q->q_retry_count);            if (now < retry_time)	continue;            sres_resend_dns_query(res, q, 1);      if (q != res->res_queries->qt_table[i])	i--;    }  }  /** Every 30 seconds it goes through the cache and removes outdated entries. */  if (res->res_now > res->res_cache_cleaned + SRES_CACHE_TIMER_INTERVAL) {    /* Clean cache from old entries */    res->res_cache_cleaned = res->res_now;    for (i = 0; i < res->res_cache->ht_size; i++) {      sres_rr_hash_entry_t *e;            while ((e = res->res_cache->ht_table[i]) != NULL) {	if (res->res_now - e->rr_received <= e->rr->sr_ttl)	  break;		sres_htable_remove(res->res_cache, e);      	_sres_free_answer(res, e->rr);      }    }  }  UNLOCK(res);}/** Resend DNS query, report error cannot resend any more. */voidsres_resend_dns_query(sres_resolver_t *res, sres_query_t *q, int timeout){  int i, N;  SU_DEBUG_9(("sres_resend_dns_query(%p, %p, %u) called\n",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -