📄 sres.c
字号:
} else if (MATCH("search")) { if (localdomain) /* LOCALDOMAIN overrides */ continue; if (search) su_free(home, search), search = NULL; if (domain) su_free(home, domain), domain = NULL; search = su_strdup(home, value); if (!search) return -1; } else if (MATCH("port")) { unsigned long port = strtoul(value, NULL, 10); if (port < 65536) c->c_port = port; } else if (MATCH("options")) { sres_parse_options(c, value); } } } if (f) c->c_modified = sres_config_timestamp(c); if (localdomain) c->c_search[0] = localdomain; else if (domain) c->c_search[0] = domain; else if (search) { for (i = 0; search[0] && i < SRES_MAX_SEARCH; i++) { c->c_search[i] = search; search += strcspn(search, " \t"); if (*search) { *search++ = '\0'; search += strspn(search, " \t"); } } } return i;}static int sres_parse_options(sres_config_t *c, char const *value){ if (!value) return -1; while (value[0]) { char const *b; int len, extra = 0; unsigned long n = 0; b = value; len = strcspn(value, " \t:"); value += len; if (value[0] == ':') { len++; n = strtoul(++value, NULL, 10); value += extra = strcspn(value, " \t"); } if (*value) value += strspn(value, " \t"); if (n > 65536) { SU_DEBUG_3(("sres: %s: invalid %*.s\n", c->c_filename, len + extra, b)); continue; } /* Documented by BIND9 resolv.conf */ if (MATCH("no-debug")) c->c_opt.debug = 0; else if (MATCH("debug")) c->c_opt.debug = 1; else if (MATCH("ndots:")) c->c_opt.ndots = n; else if (MATCH("timeout:")) c->c_opt.timeout = n; else if (MATCH("attempts:")) c->c_opt.attempts = n; else if (MATCH("no-rotate")) c->c_opt.rotate = 0; else if (MATCH("rotate")) c->c_opt.rotate = 1; else if (MATCH("no-check-names")) c->c_opt.check_names = 0; else if (MATCH("check-names")) c->c_opt.check_names = 1; else if (MATCH("no-inet6")) c->c_opt.ip6int = 0; else if (MATCH("inet6")) c->c_opt.inet6 = 1; else if (MATCH("no-ip6-dotint")) c->c_opt.ip6int = 0; else if (MATCH("ip6-dotint")) c->c_opt.ip6int = 1; else if (MATCH("no-ip6-bytestring")) c->c_opt.ip6bytestring = 0; else if (MATCH("ip6-bytestring")) c->c_opt.ip6bytestring = 1; /* Sofia-specific extensions: */ else if (MATCH("no-edns0")) c->c_opt.edns = edns_not_supported; else if (MATCH("edns0")) c->c_opt.edns = edns0_configured; else { SU_DEBUG_3(("sres: %s: unknown option %*.s\n", c->c_filename, len + extra, b)); } } return 0;}staticint sres_parse_nameserver(sres_config_t *c, char const *server){ sres_nameserver_t *ns; struct sockaddr *sa; int err, i; for (i = 0; i < SRES_MAX_NAMESERVERS; i++) if (c->c_nameservers[i] == NULL) break; if (i >= SRES_MAX_NAMESERVERS) return 0 /* Silently discard extra nameservers */; ns = su_zalloc(c->c_home, (sizeof *ns) + strlen(server) + 1); if (!ns) return -1; sa = (void *)ns->ns_addr;#if HAVE_SIN6 if (strchr(server, ':')) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; memset(sa, 0, ns->ns_addrlen = sizeof *sin6); err = inet_pton(sa->sa_family = AF_INET6, server, &sin6->sin6_addr); } else #endif { struct sockaddr_in *sin = (struct sockaddr_in *)sa; memset(sa, 0, ns->ns_addrlen = sizeof *sin); err = inet_pton(sa->sa_family = AF_INET, server, &sin->sin_addr); } if (err <= 0) { SU_DEBUG_3(("sres: nameserver %s: invalid address\n", server)); su_free(c->c_home, ns); return 0; }#if HAVE_SA_LEN sa->sa_len = ns->ns_addrlen;#endif c->c_nameservers[i] = ns; return 1;}/** Get current timestamp of resolv.conf file */statictime_t sres_config_timestamp(sres_config_t const *c){#ifndef _WIN32 struct stat st; if (stat(c->c_filename, &st) == 0) return st.st_mtime; /** @return If the resolv.conf file does not exists, return old timestamp. */ return c->c_modified;#else /** On WIN32, return always different timestamp */ return c->c_modified + SRES_UPDATE_INTERVAL_SECS;#endif}/* ---------------------------------------------------------------------- *//** Check if the new configuration has different servers than the old */static int sres_config_changed_servers(sres_config_t const *new_c, sres_config_t const *old_c){ int i; sres_nameserver_t const *new_ns, *old_ns; if (old_c == NULL) return 1; for (i = 0; i < SRES_MAX_NAMESERVERS; i++) { new_ns = new_c->c_nameservers[i]; old_ns = old_c->c_nameservers[i]; if (!new_ns != !old_ns) return 1; if (!new_ns) return 0; if (new_ns->ns_addrlen != old_ns->ns_addrlen) return 1; if (memcmp(new_ns->ns_addr, old_ns->ns_addr, new_ns->ns_addrlen)) return 1; } return 0;}/** Allocate new servers structure */staticsres_server_t **sres_servers_new(sres_resolver_t *res, sres_config_t const *c){ sres_server_t **servers, *dns; sres_nameserver_t *ns; int N, i; size_t size; for (N = 0; c->c_nameservers[N] && N < SRES_MAX_NAMESERVERS; N++) ; size = (N + 1) * (sizeof *servers) + N * (sizeof **servers); servers = su_zalloc(res->res_home, size); if (!servers) return servers; dns = (void *)(servers + N + 1); for (i = 0; i < N; i++) { dns->dns_socket = -1; ns = c->c_nameservers[i]; memcpy(dns->dns_addr, ns->ns_addr, dns->dns_addrlen = ns->ns_addrlen); inet_ntop(dns->dns_addr->ss_family, SS_ADDR(dns->dns_addr), dns->dns_name, sizeof dns->dns_name); dns->dns_edns = c->c_opt.edns; servers[i] = dns++; } return servers;}staticvoid sres_servers_unref(sres_resolver_t *res, sres_server_t **servers){ int i; if (res == NULL || servers == NULL) return; for (i = 0; i < SRES_MAX_NAMESERVERS; i++) { if (!servers[i]) break; if (servers[i]->dns_socket != -1) { if (res->res_updcb) res->res_updcb(res->res_async, -1, servers[i]->dns_socket); closesocket(servers[i]->dns_socket); } } su_free(res->res_home, servers);}staticint sres_servers_count(sres_server_t *const *servers){ int i; if (!servers) return 0; for (i = 0; i < SRES_MAX_NAMESERVERS; i++) { if (!servers[i]) break; } return i;}staticint sres_server_socket(sres_resolver_t *res, sres_server_t *dns){ int family = dns->dns_addr->ss_family; int s; if (dns->dns_socket != -1) return dns->dns_socket; s = socket(family, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) { SU_DEBUG_1(("%s: %s: %s\n", "sres_server_socket", "socket", su_strerror(su_errno()))); dns->dns_error = time(NULL); return s; }#if HAVE_IP_RECVERR if (family == AF_INET || family == AF_INET6) { int const one = 1; if (setsockopt(s, SOL_IP, IP_RECVERR, &one, sizeof(one)) < 0) { if (family == AF_INET) SU_DEBUG_3(("setsockopt(IPVRECVERR): %s\n", su_strerror(su_errno()))); } }#endif#if HAVE_IPV6_RECVERR if (family == AF_INET6) { int const one = 1; if (setsockopt(s, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one)) < 0) SU_DEBUG_3(("setsockopt(IPV6_RECVERR): %s\n", su_strerror(su_errno()))); }#endif if (connect(s, (void *)dns->dns_addr, dns->dns_addrlen) < 0) { char ipaddr[64]; char const *lb = "", *rb = ""; if (family == AF_INET) { void *addr = &((struct sockaddr_in *)dns->dns_addr)->sin_addr; inet_ntop(family, addr, ipaddr, sizeof ipaddr); }#if HAVE_SIN6 else if (family == AF_INET6) { void *addr = &((struct sockaddr_in6 *)dns->dns_addr)->sin6_addr; inet_ntop(family, addr, ipaddr, sizeof ipaddr); lb = "[", rb = "]"; }#endif else snprintf(ipaddr, sizeof ipaddr, "<af=%u>", family); SU_DEBUG_1(("%s: %s: %s: %s%s%s:%u\n", "sres_server_socket", "connect", su_strerror(su_errno()), lb, ipaddr, rb, ntohs(((struct sockaddr_in *)dns->dns_addr)->sin_port))); closesocket(s); dns->dns_error = time(NULL); return -1; } if (res->res_updcb) { if (res->res_updcb(res->res_async, s, -1) < 0) { SU_DEBUG_1(("%s: %s: %s\n", "sres_server_socket", "update callback", su_strerror(su_errno()))); closesocket(s); dns->dns_error = time(NULL); return -1; } } dns->dns_socket = s; return s;}/* ---------------------------------------------------------------------- *//** Send a query packet */static int sres_send_dns_query(sres_resolver_t *res, sres_query_t *q){ sres_message_t m[1]; uint8_t i, i0, N = res->res_n_servers; int s, transient, error = 0; 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; time_t now = res->res_now; sres_server_t **servers = res->res_servers, *dns; char b[8]; if (now == 0) time(&now); SU_DEBUG_9(("sres_send_dns_query(%p, %p) called\n", res, q)); if (domain == NULL) return -1; if (servers == 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; } transient = 0; i0 = q->q_i_server; assert(i0 < N); if (res->res_config->c_opt.rotate || servers[i0]->dns_error || servers[i0]->dns_icmp) dns = sres_next_server(res, &q->q_i_server, 0), i = q->q_i_server; else dns = servers[i0], i = i0; for (; dns; dns = sres_next_server(res, &i, 0)) { /* If server supports EDNS, include EDNS0 record */ q->q_edns = dns->dns_edns; /* 0 (no EDNS) or 1 (EDNS supported) additional data records */ m->m_arcount = htons(q->q_edns != 0); /* Size with or without EDNS record */ size = q->q_edns ? edns_size : no_edns_size; s = sres_server_socket(res, dns); /* Send the DNS message via the UDP socket */ if (s != -1 && send(s, m->m_data, size, 0) == size) break; error = su_errno(); dns->dns_icmp = now; /* EINVAL is returned if destination address is bad */ if (transient++ < 3 && error != EINVAL && s != -1) continue; transient = 0; dns->dns_error = now; /* Mark as a bad destination */ } if (!dns) { /* 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 %s %s (to [%s]:%u)\n", "sres_send_dns_query", res, q, id, sres_record_type(type, b), domain, dns->dns_name, htons(((struct sockaddr_in *)dns->dns_addr)->sin_port))); return 0;}/** Select next server */staticsres_server_t *sres_next_server(sres_resolver_t *res, uint8_t *in_out_i, int timeout){ int i, j, N; sres_server_t **servers; assert(res && in_out_i); N = res->res_n_servers; servers = res->res_servers; i = *in_out_i; assert(res->res_servers && res->res_servers[i]); /* Retry using another server? */ for (j = (i + 1) % N; (j != i); j = (j + 1) % N) { if (servers[j]->dns_icmp == 0) { return *in_out_i = j, servers[j]; } } for (j = (i + 1) % N; (j != i); j = (j + 1) % N) { if (servers[j]->dns_error == 0) { return *in_out_i = j, servers[j]; } } if (timeout) return servers[i]; return NULL;}/** * Callback function for subqueries */staticvoid sres_answer_subquery(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -