Add query retry feature
This commit is contained in:
240
src/dns_client.c
240
src/dns_client.c
@@ -54,6 +54,7 @@
|
|||||||
#define DNS_TCP_IDLE_TIMEOUT (60 * 10)
|
#define DNS_TCP_IDLE_TIMEOUT (60 * 10)
|
||||||
#define DNS_TCP_CONNECT_TIMEOUT (5)
|
#define DNS_TCP_CONNECT_TIMEOUT (5)
|
||||||
#define DNS_QUERY_TIMEOUT (500)
|
#define DNS_QUERY_TIMEOUT (500)
|
||||||
|
#define DNS_QUERY_RETRY (3)
|
||||||
|
|
||||||
#ifndef TCP_FASTOPEN_CONNECT
|
#ifndef TCP_FASTOPEN_CONNECT
|
||||||
#define TCP_FASTOPEN_CONNECT 30
|
#define TCP_FASTOPEN_CONNECT 30
|
||||||
@@ -199,6 +200,12 @@ struct dns_query_struct {
|
|||||||
dns_client_callback callback;
|
dns_client_callback callback;
|
||||||
void *user_ptr;
|
void *user_ptr;
|
||||||
|
|
||||||
|
/* retry count */
|
||||||
|
atomic_t retry_count;
|
||||||
|
|
||||||
|
/* has result */
|
||||||
|
int has_result;
|
||||||
|
|
||||||
/* replied hash table */
|
/* replied hash table */
|
||||||
DECLARE_HASHTABLE(replied_map, 4);
|
DECLARE_HASHTABLE(replied_map, 4);
|
||||||
};
|
};
|
||||||
@@ -260,8 +267,8 @@ static int _dns_client_server_exist(struct addrinfo *gai, dns_server_type_t serv
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_client_server_update_ttl(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len,
|
static void _dns_client_server_update_ttl(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr,
|
||||||
int seqno, int ttl, struct timeval *tv, void *userptr)
|
socklen_t addr_len, int seqno, int ttl, struct timeval *tv, void *userptr)
|
||||||
{
|
{
|
||||||
struct dns_server_info *server_info = userptr;
|
struct dns_server_info *server_info = userptr;
|
||||||
if (result != PING_RESULT_RESPONSE || server_info == NULL) {
|
if (result != PING_RESULT_RESPONSE || server_info == NULL) {
|
||||||
@@ -566,8 +573,8 @@ static void _dns_client_group_remove_all(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* add dns server information */
|
/* add dns server information */
|
||||||
static int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type, unsigned int server_flag, unsigned int result_flag, int ttl,
|
static int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type, unsigned int server_flag, unsigned int result_flag,
|
||||||
char *spki)
|
int ttl, char *spki)
|
||||||
{
|
{
|
||||||
struct dns_server_info *server_info = NULL;
|
struct dns_server_info *server_info = NULL;
|
||||||
unsigned char *spki_data = NULL;
|
unsigned char *spki_data = NULL;
|
||||||
@@ -773,7 +780,7 @@ static int _dns_client_server_remove(char *server_ip, struct addrinfo *gai, dns_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, unsigned int server_flag, unsigned int result_flag, int ttl,
|
static int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, unsigned int server_flag, unsigned int result_flag, int ttl,
|
||||||
char *spki, int operate)
|
char *spki, int operate)
|
||||||
{
|
{
|
||||||
char port_s[8];
|
char port_s[8];
|
||||||
int sock_type;
|
int sock_type;
|
||||||
@@ -982,48 +989,6 @@ static void _dns_client_check_tcp(void)
|
|||||||
pthread_mutex_unlock(&client.server_list_lock);
|
pthread_mutex_unlock(&client.server_list_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_client_period_run_second(void)
|
|
||||||
{
|
|
||||||
_dns_client_check_tcp();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _dns_client_period_run(void)
|
|
||||||
{
|
|
||||||
struct dns_query_struct *query, *tmp;
|
|
||||||
static unsigned int msec = 0;
|
|
||||||
msec++;
|
|
||||||
|
|
||||||
LIST_HEAD(check_list);
|
|
||||||
|
|
||||||
unsigned long now = get_tick_count();
|
|
||||||
|
|
||||||
/* get query which timed out to check list */
|
|
||||||
pthread_mutex_lock(&client.domain_map_lock);
|
|
||||||
list_for_each_entry_safe(query, tmp, &client.dns_request_list, dns_request_list)
|
|
||||||
{
|
|
||||||
if ((now - DNS_QUERY_TIMEOUT >= query->send_tick) && query->send_tick > 0) {
|
|
||||||
list_add(&query->period_list, &check_list);
|
|
||||||
_dns_client_query_get(query);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&client.domain_map_lock);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(query, tmp, &check_list, period_list)
|
|
||||||
{
|
|
||||||
/* free timed out query, and notify caller */
|
|
||||||
list_del_init(&query->period_list);
|
|
||||||
_dns_client_check_udp_nat(query);
|
|
||||||
_dns_client_query_remove(query);
|
|
||||||
_dns_client_query_release(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msec % 10 == 0) {
|
|
||||||
_dns_client_period_run_second();
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char *domain)
|
static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char *domain)
|
||||||
{
|
{
|
||||||
struct dns_query_struct *query = NULL;
|
struct dns_query_struct *query = NULL;
|
||||||
@@ -1163,6 +1128,10 @@ static int _dns_client_recv(struct dns_server_info *server_info, unsigned char *
|
|||||||
/* if all server replied, or done, stop query, release resource */
|
/* if all server replied, or done, stop query, release resource */
|
||||||
_dns_client_query_remove(query);
|
_dns_client_query_remove(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
query->has_result = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_dns_client_query_release(query);
|
_dns_client_query_release(query);
|
||||||
@@ -1593,7 +1562,7 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
tlog(TLOG_ERROR, "recv failed, %s\n", strerror(errno));
|
tlog(TLOG_ERROR, "recv failed, server %s, %s\n", server_info->ip, strerror(errno));
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1899,55 +1868,6 @@ static int _dns_client_process(struct dns_server_info *server_info, struct epoll
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *_dns_client_work(void *arg)
|
|
||||||
{
|
|
||||||
struct epoll_event events[DNS_MAX_EVENTS + 1];
|
|
||||||
int num;
|
|
||||||
int i;
|
|
||||||
unsigned long now = {0};
|
|
||||||
unsigned int sleep = 100;
|
|
||||||
int sleep_time;
|
|
||||||
unsigned long expect_time = 0;
|
|
||||||
|
|
||||||
sleep_time = sleep;
|
|
||||||
now = get_tick_count() - sleep;
|
|
||||||
expect_time = now + sleep;
|
|
||||||
while (client.run) {
|
|
||||||
now = get_tick_count();
|
|
||||||
if (now >= expect_time) {
|
|
||||||
_dns_client_period_run();
|
|
||||||
sleep_time = sleep - (now - expect_time);
|
|
||||||
if (sleep_time < 0) {
|
|
||||||
sleep_time = 0;
|
|
||||||
expect_time = now;
|
|
||||||
}
|
|
||||||
expect_time += sleep;
|
|
||||||
}
|
|
||||||
|
|
||||||
num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time);
|
|
||||||
if (num < 0) {
|
|
||||||
usleep(100000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
struct epoll_event *event = &events[i];
|
|
||||||
struct dns_server_info *server_info = (struct dns_server_info *)event->data.ptr;
|
|
||||||
if (server_info == NULL) {
|
|
||||||
tlog(TLOG_WARN, "server info is invalid.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_dns_client_process(server_info, event, now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close(client.epoll_fd);
|
|
||||||
client.epoll_fd = -1;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len)
|
static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len)
|
||||||
{
|
{
|
||||||
int send_len = 0;
|
int send_len = 0;
|
||||||
@@ -2221,12 +2141,14 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
|
|||||||
INIT_LIST_HEAD(&query->dns_request_list);
|
INIT_LIST_HEAD(&query->dns_request_list);
|
||||||
atomic_set(&query->refcnt, 0);
|
atomic_set(&query->refcnt, 0);
|
||||||
atomic_set(&query->dns_request_sent, 0);
|
atomic_set(&query->dns_request_sent, 0);
|
||||||
|
atomic_set(&query->retry_count, DNS_QUERY_RETRY);
|
||||||
hash_init(query->replied_map);
|
hash_init(query->replied_map);
|
||||||
strncpy(query->domain, domain, DNS_MAX_CNAME_LEN);
|
strncpy(query->domain, domain, DNS_MAX_CNAME_LEN);
|
||||||
query->user_ptr = user_ptr;
|
query->user_ptr = user_ptr;
|
||||||
query->callback = callback;
|
query->callback = callback;
|
||||||
query->qtype = qtype;
|
query->qtype = qtype;
|
||||||
query->send_tick = 0;
|
query->send_tick = 0;
|
||||||
|
query->has_result = 0;
|
||||||
query->sid = atomic_inc_return(&dns_client_sid);
|
query->sid = atomic_inc_return(&dns_client_sid);
|
||||||
query->server_group = _dns_client_get_dnsserver_group(group_name);
|
query->server_group = _dns_client_get_dnsserver_group(group_name);
|
||||||
if (query->server_group == NULL) {
|
if (query->server_group == NULL) {
|
||||||
@@ -2270,6 +2192,130 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _dns_client_check_servers(void)
|
||||||
|
{
|
||||||
|
struct dns_server_info *server_info, *tmp;
|
||||||
|
static unsigned int second_count = 0;
|
||||||
|
|
||||||
|
second_count++;
|
||||||
|
if (second_count % 60 != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&client.server_list_lock);
|
||||||
|
list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list)
|
||||||
|
{
|
||||||
|
if (server_info->type != DNS_SERVER_UDP) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server_info->last_send - 600 > server_info->last_recv) {
|
||||||
|
server_info->recv_buff.len = 0;
|
||||||
|
server_info->send_buff.len = 0;
|
||||||
|
tlog(TLOG_DEBUG, "server %s may failure.", server_info->ip);
|
||||||
|
_dns_client_close_socket(server_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&client.server_list_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _dns_client_period_run_second(void)
|
||||||
|
{
|
||||||
|
_dns_client_check_tcp();
|
||||||
|
_dns_client_check_servers();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _dns_client_period_run(void)
|
||||||
|
{
|
||||||
|
struct dns_query_struct *query, *tmp;
|
||||||
|
static unsigned int msec = 0;
|
||||||
|
msec++;
|
||||||
|
|
||||||
|
LIST_HEAD(check_list);
|
||||||
|
|
||||||
|
unsigned long now = get_tick_count();
|
||||||
|
|
||||||
|
/* get query which timed out to check list */
|
||||||
|
pthread_mutex_lock(&client.domain_map_lock);
|
||||||
|
list_for_each_entry_safe(query, tmp, &client.dns_request_list, dns_request_list)
|
||||||
|
{
|
||||||
|
if ((now - DNS_QUERY_TIMEOUT >= query->send_tick) && query->send_tick > 0) {
|
||||||
|
list_add(&query->period_list, &check_list);
|
||||||
|
_dns_client_query_get(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&client.domain_map_lock);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(query, tmp, &check_list, period_list)
|
||||||
|
{
|
||||||
|
/* free timed out query, and notify caller */
|
||||||
|
list_del_init(&query->period_list);
|
||||||
|
_dns_client_check_udp_nat(query);
|
||||||
|
if (atomic_dec_and_test(&query->retry_count) || (query->has_result != 0)) {
|
||||||
|
_dns_client_query_remove(query);
|
||||||
|
} else {
|
||||||
|
tlog(TLOG_DEBUG, "retry query %s", query->domain);
|
||||||
|
_dns_client_send_query(query, query->domain);
|
||||||
|
}
|
||||||
|
_dns_client_query_release(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msec % 10 == 0) {
|
||||||
|
_dns_client_period_run_second();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *_dns_client_work(void *arg)
|
||||||
|
{
|
||||||
|
struct epoll_event events[DNS_MAX_EVENTS + 1];
|
||||||
|
int num;
|
||||||
|
int i;
|
||||||
|
unsigned long now = {0};
|
||||||
|
unsigned int sleep = 100;
|
||||||
|
int sleep_time;
|
||||||
|
unsigned long expect_time = 0;
|
||||||
|
|
||||||
|
sleep_time = sleep;
|
||||||
|
now = get_tick_count() - sleep;
|
||||||
|
expect_time = now + sleep;
|
||||||
|
while (client.run) {
|
||||||
|
now = get_tick_count();
|
||||||
|
if (now >= expect_time) {
|
||||||
|
_dns_client_period_run();
|
||||||
|
sleep_time = sleep - (now - expect_time);
|
||||||
|
if (sleep_time < 0) {
|
||||||
|
sleep_time = 0;
|
||||||
|
expect_time = now;
|
||||||
|
}
|
||||||
|
expect_time += sleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time);
|
||||||
|
if (num < 0) {
|
||||||
|
usleep(100000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
struct epoll_event *event = &events[i];
|
||||||
|
struct dns_server_info *server_info = (struct dns_server_info *)event->data.ptr;
|
||||||
|
if (server_info == NULL) {
|
||||||
|
tlog(TLOG_WARN, "server info is invalid.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dns_client_process(server_info, event, now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(client.epoll_fd);
|
||||||
|
client.epoll_fd = -1;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int dns_client_set_ecs(char *ip, int subnet)
|
int dns_client_set_ecs(char *ip, int subnet)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -144,6 +144,8 @@ struct dns_request {
|
|||||||
|
|
||||||
atomic_t adblock;
|
atomic_t adblock;
|
||||||
|
|
||||||
|
atomic_t soa_num;
|
||||||
|
|
||||||
/* send original raw packet to server/client like proxy */
|
/* send original raw packet to server/client like proxy */
|
||||||
int passthrough;
|
int passthrough;
|
||||||
int request_wait;
|
int request_wait;
|
||||||
@@ -577,6 +579,8 @@ static int _dns_server_request_complete(struct dns_request *request)
|
|||||||
/* insert result to cache */
|
/* insert result to cache */
|
||||||
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ping_ttl_v6);
|
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ping_ttl_v6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request->has_soa = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request->has_ipv4 && request->ping_ttl_v4 > 0) {
|
if (request->has_ipv4 && request->ping_ttl_v4 > 0) {
|
||||||
@@ -594,10 +598,9 @@ static int _dns_server_request_complete(struct dns_request *request)
|
|||||||
|
|
||||||
return _dns_server_reply_SOA(DNS_RC_NOERROR, request, NULL);
|
return _dns_server_reply_SOA(DNS_RC_NOERROR, request, NULL);
|
||||||
}
|
}
|
||||||
request->has_ipv4 = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
request->has_soa = 0;
|
request->has_ipv4 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request->has_soa) {
|
if (request->has_soa) {
|
||||||
@@ -949,6 +952,23 @@ match:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _dns_server_is_adblock_ipv6(unsigned char addr[16])
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 15; i++) {
|
||||||
|
if (addr[i]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr[15] == 0 || addr[15] == 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _dns_server_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet, unsigned int result_flag)
|
static int _dns_server_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet, unsigned int result_flag)
|
||||||
{
|
{
|
||||||
int ttl;
|
int ttl;
|
||||||
@@ -1086,6 +1106,15 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ad blocking result */
|
||||||
|
if (_dns_server_is_adblock_ipv6(addr) == 0) {
|
||||||
|
/* If half of the servers return the same result, then the domain name result is the IP address. */
|
||||||
|
if (atomic_inc_return(&request->adblock) <= dns_server_num() / 2) {
|
||||||
|
_dns_server_request_release(request);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* add this ip to reqeust */
|
/* add this ip to reqeust */
|
||||||
if (_dns_ip_address_check_add(request, addr, DNS_T_AAAA) != 0) {
|
if (_dns_ip_address_check_add(request, addr, DNS_T_AAAA) != 0) {
|
||||||
_dns_server_request_release(request);
|
_dns_server_request_release(request);
|
||||||
@@ -1122,6 +1151,9 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
|||||||
tlog(TLOG_DEBUG, "domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: %d, minimum: %d", domain,
|
tlog(TLOG_DEBUG, "domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: %d, minimum: %d", domain,
|
||||||
request->qtype, request->soa.mname, request->soa.rname, request->soa.serial, request->soa.refresh, request->soa.retry, request->soa.expire,
|
request->qtype, request->soa.mname, request->soa.rname, request->soa.serial, request->soa.refresh, request->soa.retry, request->soa.expire,
|
||||||
request->soa.minimum);
|
request->soa.minimum);
|
||||||
|
if (atomic_inc_return(&request->soa_num) >= (dns_server_num() / 2)) {
|
||||||
|
_dns_server_request_complete(request);
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
tlog(TLOG_DEBUG, "%s, qtype: %d", name, rrs->type);
|
tlog(TLOG_DEBUG, "%s, qtype: %d", name, rrs->type);
|
||||||
@@ -1533,6 +1565,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
|||||||
memset(request, 0, sizeof(*request));
|
memset(request, 0, sizeof(*request));
|
||||||
pthread_mutex_init(&request->ip_map_lock, NULL);
|
pthread_mutex_init(&request->ip_map_lock, NULL);
|
||||||
atomic_set(&request->adblock, 0);
|
atomic_set(&request->adblock, 0);
|
||||||
|
atomic_set(&request->soa_num, 0);
|
||||||
atomic_set(&request->refcnt, 0);
|
atomic_set(&request->refcnt, 0);
|
||||||
request->ping_ttl_v4 = -1;
|
request->ping_ttl_v4 = -1;
|
||||||
request->ping_ttl_v6 = -1;
|
request->ping_ttl_v6 = -1;
|
||||||
|
|||||||
Reference in New Issue
Block a user