|
|
@@ -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)
|
|
|
-{
|
|
|
- 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_server_request_complete_A(struct dns_request *request)
|
|
|
+static int _dns_server_request_complete(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 (atomic_inc_return(&request->notified) != 1) {
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
- 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,165 +830,151 @@ 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;
|
|
|
- }
|
|
|
+ } else if (request->qtype == DNS_T_AAAA) {
|
|
|
+ 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 (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
|
|
|
- goto errout;
|
|
|
- }
|
|
|
+ if (request->has_ping_result == 0 && request->ttl_v6 > DNS_SERVER_TMOUT_TTL) {
|
|
|
+ request->ttl_v6 = DNS_SERVER_TMOUT_TTL;
|
|
|
+ }
|
|
|
|
|
|
- return 0;
|
|
|
+ request->has_soa = 0;
|
|
|
+ }
|
|
|
|
|
|
-errout:
|
|
|
- if (cache_data) {
|
|
|
- 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]);
|
|
|
|
|
|
- return -1;
|
|
|
-}
|
|
|
+ /* 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
|
|
|
|
|
|
-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->dualstack_selection) {
|
|
|
+ if (_dns_server_reply_SOA(DNS_RC_NOERROR, request) == 0) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (request->has_cname) {
|
|
|
- cname = request->cname;
|
|
|
- cname_ttl = request->ttl_cname;
|
|
|
+ request->has_ipv4 = 0;
|
|
|
}
|
|
|
|
|
|
- cache_data = dns_cache_new_data();
|
|
|
- if (cache_data == NULL) {
|
|
|
- goto errout;
|
|
|
+ if (request->has_soa) {
|
|
|
+ tlog(TLOG_INFO, "result: %s, qtype: %d, SOA", request->domain, request->qtype);
|
|
|
}
|
|
|
|
|
|
- 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);
|
|
|
+ /* update ipset */
|
|
|
+ _dns_setup_ipset(request);
|
|
|
|
|
|
- request->has_soa = 0;
|
|
|
- } else if (request->has_soa) {
|
|
|
- dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl);
|
|
|
- }
|
|
|
+ _dns_result_callback(request);
|
|
|
|
|
|
- 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->prefetch) {
|
|
|
+ return 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]);
|
|
|
+ /* return result to client */
|
|
|
+ _dns_reply(request, 1);
|
|
|
|
|
|
- /* 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;
|
|
|
- }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- 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;
|
|
|
- }
|
|
|
+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 (request->dualstack_selection) {
|
|
|
- if (_dns_server_reply_SOA(DNS_RC_NOERROR, request) != 0) {
|
|
|
- ret = -1;
|
|
|
- goto errout;
|
|
|
- }
|
|
|
+ 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;
|
|
|
+ }
|
|
|
|
|
|
- ret = 1;
|
|
|
- goto errout;
|
|
|
+ /* 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);
|
|
|
|
|
|
- request->has_ipv4 = 0;
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
-errout:
|
|
|
- if (cache_data != NULL) {
|
|
|
- dns_cache_data_free(cache_data);
|
|
|
- cache_data = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- return ret;
|
|
|
+ return addr_map;
|
|
|
}
|
|
|
|
|
|
-static int _dns_server_request_complete(struct dns_request *request)
|
|
|
+static int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr, dns_type_t addr_type)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
+ uint32_t key = 0;
|
|
|
+ struct dns_ip_address *addr_map = NULL;
|
|
|
+ int addr_len = 0;
|
|
|
|
|
|
- if (atomic_inc_return(&request->notified) != 1) {
|
|
|
- return 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;
|
|
|
}
|
|
|
|
|
|
- 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;
|
|
|
+ /* 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;
|
|
|
}
|
|
|
- tlog(TLOG_ERROR, "complete DNS A failed.");
|
|
|
- return -1;
|
|
|
}
|
|
|
}
|
|
|
+ request->ip_map_num++;
|
|
|
|
|
|
- if (request->has_soa) {
|
|
|
- tlog(TLOG_INFO, "result: %s, qtype: %d, SOA", request->domain, request->qtype);
|
|
|
- }
|
|
|
-
|
|
|
- /* update ipset */
|
|
|
- _dns_setup_ipset(request);
|
|
|
-
|
|
|
- _dns_result_callback(request);
|
|
|
-
|
|
|
- if (request->prefetch) {
|
|
|
- return 0;
|
|
|
+ addr_map = malloc(sizeof(*addr_map));
|
|
|
+ if (addr_map == NULL) {
|
|
|
+ pthread_mutex_unlock(&request->ip_map_lock);
|
|
|
+ tlog(TLOG_ERROR, "malloc failed");
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
- /* return result to client */
|
|
|
- _dns_reply(request);
|
|
|
+ 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;
|