📄 sresolv.c
字号:
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 + -