Feature: select all best ip
This commit is contained in:
611
src/dns_server.c
611
src/dns_server.c
@@ -126,6 +126,7 @@ struct dns_ip_address {
|
||||
struct hlist_node node;
|
||||
int hitnum;
|
||||
unsigned long recv_tick;
|
||||
int ping_ttl;
|
||||
dns_type_t addr_type;
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
@@ -397,15 +398,15 @@ static int _dns_add_rrs(struct dns_packet *packet, struct dns_request *request)
|
||||
|
||||
/* add A record */
|
||||
if (request->has_ipv4 && request->qtype == DNS_T_A) {
|
||||
ret |= dns_add_A(packet, DNS_RRS_AN, domain, request->ttl_v4, request->ipv4_addr);
|
||||
ret |= dns_add_A(packet, DNS_RRS_AN, domain, 3, request->ipv4_addr);
|
||||
}
|
||||
|
||||
/* add AAAA record */
|
||||
if (request->has_ipv6 && request->qtype == DNS_T_AAAA) {
|
||||
if (request->has_ipv4) {
|
||||
ret |= dns_add_A(packet, DNS_RRS_AN, domain, request->ttl_v4, request->ipv4_addr);
|
||||
ret |= dns_add_A(packet, DNS_RRS_AN, domain, 3, request->ipv4_addr);
|
||||
}
|
||||
ret |= dns_add_AAAA(packet, DNS_RRS_AN, domain, request->ttl_v6, request->ipv6_addr);
|
||||
ret |= dns_add_AAAA(packet, DNS_RRS_AN, domain, 3, request->ipv6_addr);
|
||||
}
|
||||
|
||||
/* add SOA record */
|
||||
@@ -536,7 +537,69 @@ static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpac
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_reply(struct dns_request *request)
|
||||
static int _dns_server_request_update_cache(struct dns_request *request, dns_type_t qtype,
|
||||
struct dns_cache_data *cache_data)
|
||||
{
|
||||
int ttl;
|
||||
int speed = 0;
|
||||
|
||||
if (qtype == DNS_T_A) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ttl_v4);
|
||||
speed = request->ping_ttl_v4;
|
||||
} else if (qtype == DNS_T_AAAA) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ttl_v6);
|
||||
speed = request->ping_ttl_v6;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (request->has_soa) {
|
||||
ttl = dns_conf_rr_ttl;
|
||||
}
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (request->prefetch) {
|
||||
if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
if (dns_cache_insert(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (cache_data) {
|
||||
dns_cache_data_free(cache_data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_cache_reply_packet(struct dns_request *request, unsigned char *inpacket, int inpacket_len)
|
||||
{
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (request->qtype != DNS_T_AAAA && request->qtype != DNS_T_A) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_cache_data *cache_packet = dns_cache_new_data_packet(request->server_flags, inpacket, inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_dns_server_request_update_cache(request, request->qtype, cache_packet) != 0) {
|
||||
tlog(TLOG_WARN, "update packet cache failed.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_reply(struct dns_request *request, int docache)
|
||||
{
|
||||
unsigned char inpacket[DNS_IN_PACKSIZE];
|
||||
unsigned char packet_buff[DNS_PACKSIZE];
|
||||
@@ -587,6 +650,14 @@ static int _dns_reply(struct dns_request *request)
|
||||
|
||||
/* send request */
|
||||
atomic_inc_return(&request->notified);
|
||||
|
||||
if (docache) {
|
||||
ret = _dns_cache_reply_packet(request, inpacket, encode_len);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_WARN, "cache packet for %s failed.", request->domain);
|
||||
}
|
||||
}
|
||||
|
||||
return _dns_reply_inpacket(request, inpacket, encode_len);
|
||||
}
|
||||
|
||||
@@ -674,7 +745,7 @@ static int _dns_server_reply_SOA(int rcode, struct dns_request *request)
|
||||
|
||||
_dns_result_callback(request);
|
||||
|
||||
_dns_reply(request);
|
||||
_dns_reply(request, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -745,63 +816,13 @@ static int _dns_setup_ipset(struct dns_request *request)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_request_update_cache(struct dns_request *request, dns_type_t qtype,
|
||||
struct dns_cache_data *cache_data)
|
||||
static int _dns_server_request_complete(struct dns_request *request)
|
||||
{
|
||||
int ttl;
|
||||
int speed = 0;
|
||||
|
||||
if (qtype == DNS_T_A) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ttl_v4);
|
||||
speed = request->ping_ttl_v4;
|
||||
} else if (qtype == DNS_T_AAAA) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ttl_v6);
|
||||
speed = request->ping_ttl_v6;
|
||||
} else {
|
||||
goto errout;
|
||||
if (atomic_inc_return(&request->notified) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (request->has_soa) {
|
||||
ttl = dns_conf_rr_ttl;
|
||||
}
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (request->prefetch) {
|
||||
if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
if (dns_cache_insert(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (cache_data) {
|
||||
dns_cache_data_free(cache_data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_request_complete_A(struct dns_request *request)
|
||||
{
|
||||
char *cname = NULL;
|
||||
int cname_ttl = dns_conf_rr_ttl;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
|
||||
if (request->has_cname) {
|
||||
cname = request->cname;
|
||||
cname_ttl = request->ttl_cname;
|
||||
}
|
||||
|
||||
cache_data = dns_cache_new_data();
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (request->has_ipv4 != 0) {
|
||||
if (request->qtype == DNS_T_A && request->has_ipv4 != 0) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0],
|
||||
request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
|
||||
@@ -809,148 +830,42 @@ static int _dns_server_request_complete_A(struct dns_request *request)
|
||||
if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
|
||||
request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
|
||||
}
|
||||
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
} else if (request->has_soa) {
|
||||
dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl);
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) {
|
||||
dns_cache_data_free(cache_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (cache_data) {
|
||||
dns_cache_data_free(cache_data);
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_request_complete_AAAA(struct dns_request *request)
|
||||
{
|
||||
int ret = -1;
|
||||
char *cname = NULL;
|
||||
int cname_ttl = dns_conf_rr_ttl;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
|
||||
if (request->has_cname) {
|
||||
cname = request->cname;
|
||||
cname_ttl = request->ttl_cname;
|
||||
}
|
||||
|
||||
cache_data = dns_cache_new_data();
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (request->has_ipv6) {
|
||||
tlog(TLOG_INFO,
|
||||
"result: %s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, request->rcode, request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2],
|
||||
request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5], request->ipv6_addr[6],
|
||||
request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10],
|
||||
request->ipv6_addr[11], request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14],
|
||||
request->ipv6_addr[15]);
|
||||
|
||||
if (request->has_ping_result == 0 && request->ttl_v6 > DNS_SERVER_TMOUT_TTL) {
|
||||
request->ttl_v6 = DNS_SERVER_TMOUT_TTL;
|
||||
}
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv6_addr, DNS_T_AAAA);
|
||||
|
||||
request->has_soa = 0;
|
||||
} else if (request->has_soa) {
|
||||
dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl);
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
|
||||
if (_dns_server_request_update_cache(request, DNS_T_AAAA, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
cache_data = NULL;
|
||||
} else {
|
||||
dns_cache_data_free(cache_data);
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
if (request->has_ipv4 && (request->ping_ttl_v4 > 0)) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0],
|
||||
request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
|
||||
/* if ipv4 is fasting than ipv6, add ipv4 to cache, and return SOA for AAAA request */
|
||||
if ((request->ping_ttl_v4 + (dns_conf_dualstack_ip_selection_threshold * 10)) < request->ping_ttl_v6 ||
|
||||
request->ping_ttl_v6 < 0) {
|
||||
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
|
||||
cache_data = dns_cache_new_data();
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv4_addr,
|
||||
DNS_T_A);
|
||||
if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
if (request->dualstack_selection) {
|
||||
if (_dns_server_reply_SOA(DNS_RC_NOERROR, request) != 0) {
|
||||
ret = -1;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request->has_ipv4 = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (cache_data != NULL) {
|
||||
dns_cache_data_free(cache_data);
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_request_complete(struct dns_request *request)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (atomic_inc_return(&request->notified) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_A) {
|
||||
if (_dns_server_request_complete_A(request) != 0) {
|
||||
tlog(TLOG_ERROR, "complete DNS A failed.");
|
||||
return -1;
|
||||
}
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
ret = _dns_server_request_complete_AAAA(request);
|
||||
if (ret != 0) {
|
||||
if (ret == 1) {
|
||||
return 0;
|
||||
if (request->has_ipv6) {
|
||||
tlog(TLOG_INFO,
|
||||
"result: %s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, request->rcode, request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2],
|
||||
request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5], request->ipv6_addr[6],
|
||||
request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10],
|
||||
request->ipv6_addr[11], request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14],
|
||||
request->ipv6_addr[15]);
|
||||
|
||||
if (request->has_ping_result == 0 && request->ttl_v6 > DNS_SERVER_TMOUT_TTL) {
|
||||
request->ttl_v6 = DNS_SERVER_TMOUT_TTL;
|
||||
}
|
||||
tlog(TLOG_ERROR, "complete DNS A failed.");
|
||||
return -1;
|
||||
|
||||
request->has_soa = 0;
|
||||
}
|
||||
|
||||
if (request->has_ipv4 && (request->ping_ttl_v4 > 0)) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode,
|
||||
request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
|
||||
/* if ipv4 is fasting than ipv6, add ipv4 to cache, and return SOA for AAAA request */
|
||||
if ((request->ping_ttl_v4 + (dns_conf_dualstack_ip_selection_threshold * 10)) < request->ping_ttl_v6 ||
|
||||
request->ping_ttl_v6 < 0) {
|
||||
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
|
||||
// TODO cache ipv4 result
|
||||
|
||||
if (request->dualstack_selection) {
|
||||
if (_dns_server_reply_SOA(DNS_RC_NOERROR, request) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request->has_ipv4 = 0;
|
||||
}
|
||||
|
||||
if (request->has_soa) {
|
||||
@@ -967,7 +882,99 @@ static int _dns_server_request_complete(struct dns_request *request)
|
||||
}
|
||||
|
||||
/* return result to client */
|
||||
_dns_reply(request);
|
||||
_dns_reply(request, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_ip_address *_dns_ip_address_get(struct dns_request *request, unsigned char *addr, dns_type_t addr_type)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_ip_address *addr_map = NULL;
|
||||
struct dns_ip_address *addr_tmp = NULL;
|
||||
int addr_len = 0;
|
||||
|
||||
if (addr_type == DNS_T_A) {
|
||||
addr_len = DNS_RR_A_LEN;
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
addr_len = DNS_RR_AAAA_LEN;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* store the ip address and the number of hits */
|
||||
key = jhash(addr, addr_len, 0);
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_possible(request->ip_map, addr_tmp, node, key)
|
||||
{
|
||||
if (addr_type == DNS_T_A) {
|
||||
if (memcmp(addr_tmp->ipv4_addr, addr, addr_len) == 0) {
|
||||
addr_map = addr_tmp;
|
||||
break;
|
||||
}
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
if (memcmp(addr_tmp->ipv6_addr, addr, addr_len) == 0) {
|
||||
addr_map = addr_tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
|
||||
return addr_map;
|
||||
}
|
||||
|
||||
static int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr, dns_type_t addr_type)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_ip_address *addr_map = NULL;
|
||||
int addr_len = 0;
|
||||
|
||||
if (addr_type == DNS_T_A) {
|
||||
addr_len = DNS_RR_A_LEN;
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
addr_len = DNS_RR_AAAA_LEN;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* store the ip address and the number of hits */
|
||||
key = jhash(addr, addr_len, 0);
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_possible(request->ip_map, addr_map, node, key)
|
||||
{
|
||||
if (addr_type == DNS_T_A) {
|
||||
if (memcmp(addr_map->ipv4_addr, addr, addr_len) == 0) {
|
||||
addr_map->hitnum++;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
return -1;
|
||||
}
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
if (memcmp(addr_map->ipv6_addr, addr, addr_len) == 0) {
|
||||
addr_map->hitnum++;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
request->ip_map_num++;
|
||||
|
||||
addr_map = malloc(sizeof(*addr_map));
|
||||
if (addr_map == NULL) {
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
tlog(TLOG_ERROR, "malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_map->addr_type = addr_type;
|
||||
addr_map->hitnum = 1;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
addr_map->ping_ttl = -1;
|
||||
memcpy(addr_map->addr, addr, addr_len);
|
||||
hash_add(request->ip_map, &addr_map->node, key);
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1068,6 +1075,115 @@ static void _dns_server_delete_request(struct dns_request *request)
|
||||
free(request);
|
||||
}
|
||||
|
||||
static void _dns_server_setup_multi_ip_cache(struct dns_request *request)
|
||||
{
|
||||
struct dns_ip_address *addr_map;
|
||||
struct hlist_node *tmp;
|
||||
int bucket = 0;
|
||||
|
||||
unsigned char inpacket[DNS_IN_PACKSIZE];
|
||||
unsigned char packet_buff[DNS_PACKSIZE];
|
||||
char *domain;
|
||||
struct dns_packet *packet = (struct dns_packet *)packet_buff;
|
||||
struct dns_head head;
|
||||
int ret = 0;
|
||||
int encode_len = 0;
|
||||
int ip_num = 0;
|
||||
int ignore_speed = 0;
|
||||
int maxhit = 0;
|
||||
|
||||
memset(&head, 0, sizeof(head));
|
||||
head.id = request->id;
|
||||
head.qr = DNS_QR_ANSWER;
|
||||
head.opcode = DNS_OP_QUERY;
|
||||
head.rd = 1;
|
||||
head.ra = 1;
|
||||
head.aa = 0;
|
||||
head.tc = 0;
|
||||
head.rcode = request->rcode;
|
||||
|
||||
/* init a new DNS packet */
|
||||
ret = dns_packet_init(packet, DNS_PACKSIZE, &head);
|
||||
if (ret != 0) {
|
||||
return;
|
||||
}
|
||||
domain = request->domain;
|
||||
|
||||
/* add request domain */
|
||||
ret = dns_add_domain(packet, request->domain, request->qtype, DNS_C_IN);
|
||||
if (ret != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* add CNAME record */
|
||||
if (request->has_cname) {
|
||||
ret |= dns_add_CNAME(packet, DNS_RRS_AN, request->domain, request->ttl_cname, request->cname);
|
||||
domain = request->cname;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
{
|
||||
if (request->qtype != addr_map->addr_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addr_map->hitnum > maxhit) {
|
||||
maxhit = addr_map->hitnum;
|
||||
}
|
||||
|
||||
if (addr_map->ping_ttl < 0 && ignore_speed == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addr_map->hitnum < maxhit && ignore_speed == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addr_map->addr_type == DNS_T_A) {
|
||||
int ttl_range = request->ping_ttl_v4 + request->ping_ttl_v4 / 10;
|
||||
if ((ttl_range < addr_map->ping_ttl) && addr_map->ping_ttl >= 100 && ignore_speed == 0) {
|
||||
continue;
|
||||
}
|
||||
ret |= dns_add_A(packet, DNS_RRS_AN, domain, request->ttl_v4, addr_map->ipv4_addr);
|
||||
ip_num++;
|
||||
} else if (addr_map->addr_type == DNS_T_AAAA) {
|
||||
int ttl_range = request->ping_ttl_v6 + request->ping_ttl_v6 / 10;
|
||||
if (ttl_range < addr_map->ping_ttl && addr_map->ping_ttl >= 100 && ignore_speed == 0) {
|
||||
continue;
|
||||
}
|
||||
ret |= dns_add_AAAA(packet, DNS_RRS_AN, domain, request->ttl_v6, addr_map->ipv6_addr);
|
||||
ip_num++;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
|
||||
if (ip_num <= 0 && ignore_speed == 0) {
|
||||
ignore_speed = 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret || ip_num <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* encode to binary data */
|
||||
encode_len = dns_encode(inpacket, DNS_IN_PACKSIZE, packet);
|
||||
if (encode_len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret = _dns_cache_reply_packet(request, inpacket, encode_len);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_WARN, "cache packet for %s failed.", request->domain);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void _dns_server_request_release_complete(struct dns_request *request, int do_complete)
|
||||
{
|
||||
struct dns_ip_address *addr_map;
|
||||
@@ -1093,6 +1209,7 @@ static void _dns_server_request_release_complete(struct dns_request *request, in
|
||||
_dns_server_request_complete(request);
|
||||
}
|
||||
|
||||
_dns_server_setup_multi_ip_cache(request);
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
{
|
||||
@@ -1158,6 +1275,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
struct dns_request *request = userptr;
|
||||
int may_complete = 0;
|
||||
int threshold = 100;
|
||||
struct dns_ip_address *addr_map = NULL;
|
||||
|
||||
if (request == NULL) {
|
||||
return;
|
||||
@@ -1183,6 +1301,11 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
memcpy(request->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
|
||||
}
|
||||
|
||||
addr_map = _dns_ip_address_get(request, (unsigned char *)&addr_in->sin_addr.s_addr, DNS_T_A);
|
||||
if (addr_map) {
|
||||
addr_map->ping_ttl = rtt;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_AAAA && request->dualstack_selection) {
|
||||
if (request->ping_ttl_v6 < 0 && request->has_soa == 0) {
|
||||
return;
|
||||
@@ -1197,12 +1320,20 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
request->ping_ttl_v4 = rtt;
|
||||
request->has_ipv4 = 1;
|
||||
memcpy(request->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||
addr_map = _dns_ip_address_get(request, addr_in6->sin6_addr.s6_addr + 12, DNS_T_A);
|
||||
if (addr_map) {
|
||||
addr_map->ping_ttl = rtt;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (request->ping_ttl_v6 > rtt) {
|
||||
request->ping_ttl_v6 = rtt;
|
||||
request->has_ipv6 = 1;
|
||||
memcpy(request->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
addr_map = _dns_ip_address_get(request, addr_in6->sin6_addr.s6_addr, DNS_T_AAAA);
|
||||
if (addr_map) {
|
||||
addr_map->ping_ttl = rtt;
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -1267,60 +1398,6 @@ static int _dns_server_check_speed(struct dns_request *request, char *ip, int mo
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr, dns_type_t addr_type)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_ip_address *addr_map = NULL;
|
||||
int addr_len = 0;
|
||||
|
||||
if (addr_type == DNS_T_A) {
|
||||
addr_len = DNS_RR_A_LEN;
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
addr_len = DNS_RR_AAAA_LEN;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* store the ip address and the number of hits */
|
||||
key = jhash(addr, addr_len, 0);
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_possible(request->ip_map, addr_map, node, key)
|
||||
{
|
||||
if (addr_type == DNS_T_A) {
|
||||
if (memcmp(addr_map->ipv4_addr, addr, addr_len) == 0) {
|
||||
addr_map->hitnum++;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
return -1;
|
||||
}
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
if (memcmp(addr_map->ipv6_addr, addr, addr_len) == 0) {
|
||||
addr_map->hitnum++;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
request->ip_map_num++;
|
||||
|
||||
addr_map = malloc(sizeof(*addr_map));
|
||||
if (addr_map == NULL) {
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
tlog(TLOG_ERROR, "malloc failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr_map->addr_type = addr_type;
|
||||
addr_map->hitnum = 1;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
memcpy(addr_map->addr, addr, addr_len);
|
||||
hash_add(request->ip_map, &addr_map->node, key);
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char *addr, int addr_len,
|
||||
dns_type_t addr_type, int result_flag)
|
||||
{
|
||||
@@ -1950,17 +2027,7 @@ static int _dns_server_reply_passthrouth(struct dns_request *request, struct dns
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0 &&
|
||||
(request->qtype == DNS_T_AAAA || request->qtype == DNS_T_A)) {
|
||||
struct dns_cache_data *cache_packet = dns_cache_new_data_packet(request->server_flags, inpacket, inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (_dns_server_request_update_cache(request, request->qtype, cache_packet) != 0) {
|
||||
tlog(TLOG_WARN, "update packet cache failed.");
|
||||
}
|
||||
}
|
||||
_dns_cache_reply_packet(request, inpacket, inpacket_len);
|
||||
|
||||
if (_dns_server_setup_ipset_packet(request, packet) != 0) {
|
||||
tlog(TLOG_DEBUG, "setup ipset failed.");
|
||||
@@ -2093,7 +2160,7 @@ static int _dns_server_process_ptr(struct dns_request *request)
|
||||
|
||||
request->rcode = DNS_RC_NOERROR;
|
||||
request->has_ptr = 1;
|
||||
_dns_reply(request);
|
||||
_dns_reply(request, 0);
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return 0;
|
||||
@@ -2330,7 +2397,7 @@ static int _dns_server_process_address(struct dns_request *request)
|
||||
}
|
||||
|
||||
request->rcode = DNS_RC_NOERROR;
|
||||
_dns_reply(request);
|
||||
_dns_reply(request, 0);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
@@ -2424,7 +2491,7 @@ static int _dns_server_process_cache_addr(struct dns_request *request, struct dn
|
||||
_dns_result_callback(request);
|
||||
|
||||
if (request->prefetch == 0) {
|
||||
_dns_reply(request);
|
||||
_dns_reply(request, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2467,7 +2534,15 @@ static int _dns_server_process_cache_packet(struct dns_request *request, struct
|
||||
}
|
||||
|
||||
/* When passthrough, modify the id to be the id of the client request. */
|
||||
dns_server_update_reply_packet_id(request, cache_packet->data, cache_packet->head.size);
|
||||
struct dns_update_param param;
|
||||
param.id = request->id;
|
||||
param.cname_ttl = _dns_server_get_expired_ttl_reply(dns_cache);
|
||||
param.ip_ttl = _dns_server_get_expired_ttl_reply(dns_cache);
|
||||
if (dns_packet_update(cache_packet->data, cache_packet->head.size, ¶m) != 0) {
|
||||
tlog(TLOG_ERROR, "update cache info failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return _dns_reply_inpacket(request, cache_packet->data, cache_packet->head.size);
|
||||
errout:
|
||||
return -1;
|
||||
|
||||
Reference in New Issue
Block a user