cache: cache NXDOMAIN records.

This commit is contained in:
Nick Peng
2022-05-28 00:10:24 +08:00
parent b5a5311976
commit 2365a1a2b0

View File

@@ -46,6 +46,7 @@
#define DNS_MAX_EVENTS 256 #define DNS_MAX_EVENTS 256
#define IPV6_READY_CHECK_TIME 180 #define IPV6_READY_CHECK_TIME 180
#define DNS_SERVER_TMOUT_TTL (5 * 60) #define DNS_SERVER_TMOUT_TTL (5 * 60)
#define DNS_SERVER_FAIL_TTL (60)
#define DNS_CONN_BUFF_SIZE 4096 #define DNS_CONN_BUFF_SIZE 4096
#define DNS_REQUEST_MAX_TIMEOUT 850 #define DNS_REQUEST_MAX_TIMEOUT 850
#define DNS_PING_TIMEOUT (DNS_REQUEST_MAX_TIMEOUT) #define DNS_PING_TIMEOUT (DNS_REQUEST_MAX_TIMEOUT)
@@ -254,7 +255,8 @@ static tlog_log *dns_audit;
static int is_ipv6_ready; static int is_ipv6_ready;
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t server_flags, struct dns_query_options *options); static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t server_flags,
struct dns_query_options *options);
static int _dns_server_forward_request(unsigned char *inpacket, int inpacket_len) static int _dns_server_forward_request(unsigned char *inpacket, int inpacket_len)
{ {
@@ -1005,8 +1007,7 @@ int _dns_cache_cname_packet(struct dns_server_post_context *context)
if (inpacket_len <= 0) { if (inpacket_len <= 0) {
return -1; return -1;
} }
cache_packet = cache_packet = dns_cache_new_data_packet(request->server_flags, inpacket_buff, inpacket_len);
dns_cache_new_data_packet(request->server_flags, inpacket_buff, inpacket_len);
if (cache_packet == NULL) { if (cache_packet == NULL) {
return -1; return -1;
} }
@@ -1042,6 +1043,36 @@ errout:
return -1; return -1;
} }
static int _dns_cache_error_packet(struct dns_server_post_context *context)
{
struct dns_request *request = context->request;
struct dns_cache_data *cache_packet =
dns_cache_new_data_packet(request->server_flags, context->inpacket, context->inpacket_len);
if (cache_packet == NULL) {
return -1;
}
/* if doing prefetch, update cache only */
if (request->prefetch) {
if (dns_cache_replace(request->domain, DNS_SERVER_FAIL_TTL, context->qtype, -1, cache_packet) != 0) {
goto errout;
}
} else {
/* insert result to cache */
if (dns_cache_insert(request->domain, DNS_SERVER_FAIL_TTL, context->qtype, -1, cache_packet) != 0) {
goto errout;
}
}
return 0;
errout:
if (cache_packet) {
dns_cache_data_free(cache_packet);
}
return -1;
}
static int _dns_cache_reply_packet(struct dns_server_post_context *context) static int _dns_cache_reply_packet(struct dns_server_post_context *context)
{ {
struct dns_request *request = context->request; struct dns_request *request = context->request;
@@ -1050,6 +1081,10 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
return 0; return 0;
} }
if (context->packet->head.rcode == DNS_RC_SERVFAIL || context->packet->head.rcode == DNS_RC_NXDOMAIN) {
return _dns_cache_error_packet(context);
}
if (context->qtype != DNS_T_AAAA && context->qtype != DNS_T_A) { if (context->qtype != DNS_T_AAAA && context->qtype != DNS_T_A) {
return 0; return 0;
} }
@@ -1072,7 +1107,6 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
tlog(TLOG_WARN, "update packet cache failed."); tlog(TLOG_WARN, "update packet cache failed.");
} }
_dns_cache_cname_packet(context); _dns_cache_cname_packet(context);
return 0; return 0;
@@ -1174,7 +1208,7 @@ static int _dns_request_post(struct dns_server_post_context *context)
struct dns_request *request = context->request; struct dns_request *request = context->request;
int ret = 0; int ret = 0;
tlog(TLOG_DEBUG, "reply %s %d %d", request->domain, request->qtype, context->qtype); tlog(TLOG_DEBUG, "reply %s qtype: %d, rcode: %d", request->domain, request->qtype, context->packet->head.rcode);
if (request->conn == NULL) { if (request->conn == NULL) {
context->do_reply = 0; context->do_reply = 0;
@@ -1350,6 +1384,7 @@ static int dns_server_update_reply_packet_id(struct dns_request *request, unsign
} }
static void _dns_server_request_release(struct dns_request *request); static void _dns_server_request_release(struct dns_request *request);
static void _dns_server_request_release_complete(struct dns_request *request, int do_complete);
int _dns_server_reply_all_pending_list(struct dns_request *request, struct dns_server_post_context *context) int _dns_server_reply_all_pending_list(struct dns_request *request, struct dns_server_post_context *context)
{ {
@@ -1380,13 +1415,14 @@ int _dns_server_reply_all_pending_list(struct dns_request *request, struct dns_s
if (atomic_inc_return(&req->notified) != 1) { if (atomic_inc_return(&req->notified) != 1) {
return 0; return 0;
} }
req->rcode = request->rcode;
/* When passthrough, modify the id to be the id of the client request. */ /* When passthrough, modify the id to be the id of the client request. */
dns_server_update_reply_packet_id(req, context->inpacket, context->inpacket_len); dns_server_update_reply_packet_id(req, context->inpacket, context->inpacket_len);
ret = _dns_reply_inpacket(req, context->inpacket, context->inpacket_len); ret = _dns_reply_inpacket(req, context->inpacket, context->inpacket_len);
} }
req->request_pending_list = NULL; req->request_pending_list = NULL;
_dns_server_request_release(req); _dns_server_request_release_complete(req, 0);
} }
pthread_mutex_unlock(&pending_list->request_list_lock); pthread_mutex_unlock(&pending_list->request_list_lock);
@@ -1400,6 +1436,10 @@ static int _dns_server_request_complete(struct dns_request *request)
int force_A = 0; int force_A = 0;
int ttl = DNS_SERVER_TMOUT_TTL; int ttl = DNS_SERVER_TMOUT_TTL;
if (request->rcode == DNS_RC_SERVFAIL || request->rcode == DNS_RC_NXDOMAIN) {
ttl = DNS_SERVER_FAIL_TTL;
}
if (request->prefetch == 1) { if (request->prefetch == 1) {
return 0; return 0;
} }
@@ -2312,9 +2352,9 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
static int _dns_server_passthrough_rule_check(struct dns_request *request, char *domain, struct dns_packet *packet, static int _dns_server_passthrough_rule_check(struct dns_request *request, char *domain, struct dns_packet *packet,
unsigned int result_flag, int *pttl) unsigned int result_flag, int *pttl)
{ {
int ttl; int ttl = 0;
char name[DNS_MAX_CNAME_LEN] = {0}; char name[DNS_MAX_CNAME_LEN] = {0};
int rr_count; int rr_count = 0;
int i = 0; int i = 0;
int j = 0; int j = 0;
struct dns_rrs *rrs = NULL; struct dns_rrs *rrs = NULL;
@@ -3724,7 +3764,8 @@ static int _dns_server_do_query(struct dns_request *request)
// Get reference for AAAA query // Get reference for AAAA query
_dns_server_request_get(request); _dns_server_request_get(request);
request->request_wait++; request->request_wait++;
if (dns_client_query(request->domain, DNS_T_A, dns_server_resolve_callback, request, group_name, &options) != 0) { if (dns_client_query(request->domain, DNS_T_A, dns_server_resolve_callback, request, group_name, &options) !=
0) {
request->request_wait--; request->request_wait--;
_dns_server_request_release(request); _dns_server_request_release(request);
} }
@@ -3733,7 +3774,8 @@ static int _dns_server_do_query(struct dns_request *request)
// Get reference for DNS query // Get reference for DNS query
request->request_wait++; request->request_wait++;
_dns_server_request_get(request); _dns_server_request_get(request);
if (dns_client_query(request->domain, request->qtype, dns_server_resolve_callback, request, group_name, &options) != 0) { if (dns_client_query(request->domain, request->qtype, dns_server_resolve_callback, request, group_name, &options) !=
0) {
request->request_wait--; request->request_wait--;
_dns_server_request_release(request); _dns_server_request_release(request);
tlog(TLOG_ERROR, "send dns request failed."); tlog(TLOG_ERROR, "send dns request failed.");
@@ -3748,7 +3790,7 @@ errout:
return ret; return ret;
} }
static int _dns_server_parser_request(struct dns_request *request, struct dns_packet *packet) static int _dns_server_parser_request(struct dns_request *request, struct dns_packet *packet)
{ {
struct dns_rrs *rrs; struct dns_rrs *rrs;
int rr_count = 0; int rr_count = 0;
@@ -3780,7 +3822,6 @@ static int _dns_server_parser_request(struct dns_request *request, struct dns_pa
break; break;
} }
/* get request opts */ /* get request opts */
rr_count = 0; rr_count = 0;
rrs = dns_get_rrs_start(packet, DNS_RRS_OPT, &rr_count); rrs = dns_get_rrs_start(packet, DNS_RRS_OPT, &rr_count);
@@ -3813,7 +3854,6 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
struct dns_packet *packet = (struct dns_packet *)packet_buff; struct dns_packet *packet = (struct dns_packet *)packet_buff;
struct dns_request *request = NULL; struct dns_request *request = NULL;
/* decode packet */ /* decode packet */
tlog(TLOG_DEBUG, "recv query packet from %s, len = %d", tlog(TLOG_DEBUG, "recv query packet from %s, len = %d",
gethost_by_addr(name, sizeof(name), (struct sockaddr *)from), inpacket_len); gethost_by_addr(name, sizeof(name), (struct sockaddr *)from), inpacket_len);
@@ -3861,7 +3901,7 @@ errout:
return ret; return ret;
} }
static int _dns_server_prefetch_setup_options(struct dns_request *request, struct dns_query_options *options) static int _dns_server_prefetch_setup_options(struct dns_request *request, struct dns_query_options *options)
{ {
if (options == NULL) { if (options == NULL) {
return 0; return 0;
@@ -3875,7 +3915,8 @@ static int _dns_server_prefetch_setup_options(struct dns_request *request, struc
return 0; return 0;
} }
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t server_flags, struct dns_query_options *options) static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t server_flags,
struct dns_query_options *options)
{ {
int ret = -1; int ret = -1;
struct dns_request *request = NULL; struct dns_request *request = NULL;