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

📄 sresolv.c

📁 Internet Phone, Chat, Conferencing
💻 C
📖 第 1 页 / 共 5 页
字号:
	      res, q, timeout));    N = res->res_n_servers;  if (q->q_retry_count < SRES_MAX_RETRY_COUNT) {    for (i = (q->q_i_server + 1) % N; i != q->q_i_server; i = (i + 1) % N) {      sres_server_t *dns = res->res_servers + i;      if (dns->dns_icmp_error == 0)	break;    }    if (i == q->q_i_server && timeout)       /* All servers are unreachable... so, retry next one */      i = (i + 1) % N;    if (i != q->q_i_server || timeout) {      res->res_i_server = q->q_i_server = i;            sres_send_dns_query(res, q);      if (timeout)	q->q_retry_count++;            return;    }  }  /* report timeout/network error */  q->q_id = 0;      if (q->q_n_subs)    return;			/* let subqueries also timeout */    sres_query_report_error(res, q, NULL);}/** 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[SRES_MAXDNAME], char const *domain){  size_t len;  int already;  if (!domain)    return su_seterrno(EFAULT), (void *)NULL;  len = strlen(domain);  if (len >= SRES_MAXDNAME)    return su_seterrno(ENAMETOOLONG), (void *)NULL;  already = len > 0 && domain[len - 1] == '.';  if (already)    return domain;  if (len + 1 >= SRES_MAXDNAME)    return su_seterrno(ENAMETOOLONG), (void *)NULL;  strcpy(buf, domain);  buf[len] = '.'; buf[len + 1] = '\0';  return buf;}/** Get a server by socket address */staticsres_server_t *sres_server_by_sockaddr(sres_resolver_t const *res, 			void const *from, int fromlen){  int i;  for (i = 0; i < res->res_n_servers; i++) {    sres_server_t *dns = &res->res_servers[i];    if (dns->dns_addrlen == fromlen && 	memcmp(dns->dns_addr, from, fromlen) == 0)      return dns;  }    return NULL;}staticvoidsres_canonize_sockaddr(struct sockaddr_storage *from, socklen_t *fromlen){#if HAVE_SIN6  struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)from;  size_t sin6_addrsize =    offsetof(struct sockaddr_in6, sin6_addr) +    (sizeof sin6->sin6_addr);  if (from->ss_family == AF_INET6) {    struct in6_addr const *ip6 = &sin6->sin6_addr;      if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6)) {      /* Convert to a IPv4 address */      struct sockaddr_in *sin = (struct sockaddr_in *)from;      memcpy(&sin->sin_addr, ip6->s6_addr + 12, sizeof sin->sin_addr);      sin->sin_family = AF_INET;      *fromlen = sizeof (*sin);#if SA_LEN      sin->sin_len = sizeof (*sin);#endif    }    else if (sin6_addrsize < *fromlen) {      /* Zero extra sin6 members like sin6_flowinfo or sin6_scope_id */      memset((char *)from + sin6_addrsize, 0, *fromlen - sin6_addrsize);    }  }#endif  if (from->ss_family == AF_INET) {    struct sockaddr_in *sin = (struct sockaddr_in *)from;    memset(sin->sin_zero, 0, sizeof (sin->sin_zero));  }}#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERR#include <linux/types.h>#include <linux/errqueue.h>#include <sys/uio.h>#endif/** Create connected sockets for resolver. */int sres_resolver_sockets(sres_resolver_t const *res,			  int *sockets, int n){  int s = -1, i = 0, family = 0, retval;  int one = 1, zero = 0;  int error = su_errno();  char const *what = "socket";  struct sockaddr_storage name;  socklen_t namelen;  unsigned short port;  if (res == NULL)    return su_seterrno(EFAULT);  if (!sockets || n == 0)    return 1 + res->res_n_servers;  retval = 1 + res->res_n_servers;#if HAVE_SIN6 && 0  /* XXX - disable this until we define better API for sockets */  s = socket(family = AF_INET6, SOCK_DGRAM, IPPROTO_UDP);  namelen = sizeof(struct sockaddr_in6);#endif  if (s == -1) {    s = socket(family = AF_INET, SOCK_DGRAM, IPPROTO_UDP);    namelen = sizeof(struct sockaddr_in);  }  if (s == -1)    return -1;  sockets[i++] = s;  memset(&name, 0, namelen);#if HAVE_SA_LEN  name.ss_len = namelen;#endif  name.ss_family = family;#if HAVE_IP_RECVERR  if (setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one)) < 0)    SU_DEBUG_3(("sres: IP_RECVERR: %s\n", su_strerror(su_errno())));#endif#if HAVE_IPV6_RECVERR  if (family == AF_INET6 &&       setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0)    SU_DEBUG_3(("sres: IPV6_RECVERR: %s\n", su_strerror(su_errno())));#endif  /*   * First socket is not connected:   * bind it to a port and obtain the port number   * so that the connected sockets will have same source port.   */  if (bind(s, (struct sockaddr *)&name, namelen) < 0) {    what = "bind"; retval = -1;   }  else if (n == 1)    ;  else if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one))	   < 0) {    what = "SO_REUSEADDR"; retval = -1;   }  else if (getsockname(s, (struct sockaddr *)&name, &namelen) < 0) {    what = "getsockname"; retval = -1;  }  else for (i = 1; i < retval && i < n;) {    sres_server_t *dns = res->res_servers + i - 1;    family = dns->dns_addr->ss_family;    s = socket(family, SOCK_DGRAM, IPPROTO_UDP);    if (s == -1) {      retval = -1;      break;    }    sockets[i++] = s;#if HAVE_IP_RECVERR    if (setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one)) < 0)      SU_DEBUG_3(("sres: IP_RECVERR: %s\n", su_strerror(su_errno())));#endif#if HAVE_IPV6_RECVERR    if (family == AF_INET6 && 	setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0)      SU_DEBUG_3(("sres: IPV6_RECVERR: %s\n", su_strerror(su_errno())));#endif#if HAVE_SIN6    if (family == AF_INET6)      namelen = sizeof(struct sockaddr_in6);    else      namelen = sizeof(struct sockaddr_in);    port = ((struct sockaddr_in *)&name)->sin_port;    memset(&name, 0, namelen);#if HAVE_SA_LEN    name.ss_len = namelen;#endif    name.ss_family = family;    ((struct sockaddr_in *)&name)->sin_port = port;#endif    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 		   (void *)&one, sizeof(one)) < 0) {      SU_DEBUG_3(("%s: %s: %s\n", "sres_resolver_sockets", "SO_REUSEADDR",		  strerror(errno)));    }    else if (bind(s, (struct sockaddr *)&name, namelen) < 0) {      SU_DEBUG_3(("%s: %s: %s\n", "sres_resolver_sockets", "bind2",		  strerror(errno)));    }    else if (connect(s, (struct sockaddr *)dns->dns_addr, dns->dns_addrlen)	     < 0) {      SU_DEBUG_3(("%s: connect: %s\n", "sres_resolver_sockets",		  strerror(errno)));    }  }  if (retval > 1) {    setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, 	       (void *)&zero, sizeof(zero));  }  else if (retval < 0) {    error = su_errno();    SU_DEBUG_3(("%s: %s: %s\n", "sres_resolver_sockets", what, 		strerror(error)));    while (i >= 0)      su_close(sockets[i--]);  }    su_seterrno(error);  return retval;}/** Receive error message from socket. */#if HAVE_IP_RECVERR || HAVE_IPV6_RECVERRint sres_resolver_error(sres_resolver_t *res, int socket){  int errcode = 0;  struct cmsghdr *c;  struct sock_extended_err *ee;  struct sockaddr_storage *from;  char control[512];  char errmsg[64 + 768];  struct iovec iov[1];  struct msghdr msg[1] = {{ 0 }};  struct sockaddr_storage name[1] = {{ 0 }};  int n;  char info[128] = "";  SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_error", res, socket));  msg->msg_name = name, msg->msg_namelen = sizeof(name);  msg->msg_iov = iov, msg->msg_iovlen = 1;  iov->iov_base = errmsg, iov->iov_len = sizeof(errmsg);  msg->msg_control = control, msg->msg_controllen = sizeof(control);  n = recvmsg(socket, msg, MSG_ERRQUEUE);  if (n < 0) {    SU_DEBUG_1(("%s: recvmsg: %s\n", __func__, su_strerror(su_errno())));    return n;  }  if ((msg->msg_flags & MSG_ERRQUEUE) != MSG_ERRQUEUE) {    SU_DEBUG_1(("%s: recvmsg: no errqueue\n", __func__));    return su_seterrno(EIO);  }  if (msg->msg_flags & MSG_CTRUNC) {    SU_DEBUG_1(("%s: extended error was truncated\n", __func__));    return su_seterrno(EIO);  }  if (msg->msg_flags & MSG_TRUNC) {    /* ICMP message may contain original message... */    SU_DEBUG_5(("%s: icmp(6) message was truncated (at %d)\n", __func__, n));  }  /* Go through the ancillary data */  for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {    if (0#if HAVE_IP_RECVERR	|| (c->cmsg_level == SOL_IP && c->cmsg_type == IP_RECVERR)#endif#if HAVE_IPV6_RECVERR	|| (c->cmsg_level == SOL_IPV6 && c->cmsg_type == IPV6_RECVERR)#endif	) {      char const *origin;      ee = (struct sock_extended_err *)CMSG_DATA(c);      from = (void *)SO_EE_OFFENDER(ee);      info[0] = '\0';      switch (ee->ee_origin) {      case SO_EE_ORIGIN_LOCAL:	strcpy(info, origin = "local");	break;      case SO_EE_ORIGIN_ICMP:	snprintf(info, sizeof(info), "%s type=%u code=%u", 		 origin = "icmp", ee->ee_type, ee->ee_code);	break;      case SO_EE_ORIGIN_ICMP6:	snprintf(info, sizeof(info), "%s type=%u code=%u", 		 origin = "icmp6", ee->ee_type, ee->ee_code);	break;      case SO_EE_ORIGIN_NONE:	strcpy(info, origin = "none");	break;      default:	strcpy(info, origin = "unknown");	break;      }      if (ee->ee_info)	snprintf(info + strlen(info), sizeof(info) - strlen(info), 		 " info=%08x", ee->ee_info);      errcode = ee->ee_errno;      if (from->ss_family != AF_UNSPEC) {	socklen_t fromlen = ((char *)c + c->cmsg_len) - (char *)from;	sres_canonize_sockaddr(from, &fromlen);	snprintf(info + strlen(info), sizeof(info) - strlen(info), 		 " reported by ");	inet_ntop(from->ss_family, SS_ADDR(from), 		  info + strlen(info), sizeof(info) - strlen(info));      }      if (msg->msg_namelen <= 0)	break;      {	int error;	socklen_t errorlen = sizeof error;	/* Get error, if any */	getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&error, &errorlen);      }            if (sres_resolver_report_error(res, socket, errcode, 				     msg->msg_name, msg->msg_namelen,				     info))	return errcode;      break;    }  }  if (errcode)    sres_resolver_report_error(res, socket, errcode, NULL, 0, info);  return errcode;}#elseint sres_resolver_error(sres_resolver_t *res, int socket){  int errcode = 0;  int errorlen = sizeof(errcode);  struct sockaddr_storage remote[1] = {{ 0 }};  socklen_t remotelen = sizeof remote;  SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_error", res, socket));  getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&errcode, &errorlen);  if (getpeername(socket, (struct sockaddr *)remote, &remotelen) == 0) {    return sres_resolver_report_error(res, socket, errcode, 				      remote, remotelen, "");  }  else    return sres_resolver_report_error(res, socket, errcode, 				      NULL, 0, "");}#endif/** Report error */staticint sres_resolver_report_error(sres_resolver_t *res,			   int socket,			   int errcode,			   struct sockaddr_storage *remote,			   socklen_t remotelen, 			   char const *info){  char buf[80];  buf[0] = '\0';  if (remote) {    sres_canonize_sockaddr(remote, &remotelen);    if (remote->ss_family == AF_INET) {      struct sockaddr_in const *sin = (struct sockaddr_in *)remote;      uint8_t const *in_addr = (uint8_t*)&sin->sin_addr;      inet_ntop(AF_INET, in_addr, buf, sizeof(buf));    } #if HAVE_SIN6    else if (remote->ss_family == AF_INET6) {      struct sockaddr_in6 const *sin6 = (struct sockaddr_in6 *)remote;      uint8_t const *in_addr = (uint8_t*)&sin6->sin6_addr;      inet_ntop(AF_INET6, in_addr, buf, sizeof(buf));    }#endif  }  SU_DEBUG_5(("sres: network error %u (%s)%s%s%s%s\n", 	      errcode, su_strerror(errcode),	      buf[0] ? " from " : "", buf, 	      info ? " by " : "",	      info ? info : ""));  if (res->res_queries->qt_used) {    /* Report error to queries */    sres_server_t *dns;    sres_query_t *q;    int i;        dns = sres_server_by_sockaddr(res, remote, remotelen);    if (dns && LOCK(res)) {      time(&res->res_now);      dns->dns_icmp_error = res->res_now;      for (i = 0; i < res->res_queries->qt_size; i++) {	q = res->res_queries->qt_table[i];      	if (!q || 	    q->q_socket != socket ||	    dns != res->res_servers + q->q_i_server)	  continue;	/* Resend query/report error to application */	sres_resend_dns_query(res, q, 1);	if (q != res->res_queries->qt_table[i])	  i--;      }      UNLOCK(res);    }  }    return 1;}/** Receive a response packet from socket. */int sres_resolver_receive(sres_resolver_t *res, int socket){  int num_bytes, error;  sres_message_t m[1];  struct sockaddr_storage from[1];  socklen_t fromlen = (sizeof from);  sres_query_t *query = NULL;  sres_record_t **reply;  sres_server_t *dns;  SU_DEBUG_9(("%s(%p, %u) called\n", "sres_resolver_receive", res, socket));  assert(res);  if (res == NULL)    return 0;  memset(m, 0, offsetof(sres_message_t, m_data));     num_bytes = recvfrom(socket, m->m_data, sizeof (m->m_data), 0,		       (struct sockaddr *)from, &fromlen);  if (num_bytes <= 0) {    SU_DEBUG_5(("%s: %s\n", "sres_receive_packet", su_strerror(su_errno())));    return 0;  }  sres_canonize_sockaddr(from, &fromlen);  dns = sres_server_by_sockaddr(res, from, fromlen);  if (!dns)    return 0;

⌨️ 快捷键说明

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