Browse Source

dualstack: cache SOA record for speed.

Nick Peng 4 years ago
parent
commit
11cf7b614c
3 changed files with 119 additions and 46 deletions
  1. 59 12
      src/dns_cache.c
  2. 10 3
      src/dns_cache.h
  3. 50 31
      src/dns_server.c

+ 59 - 12
src/dns_cache.c

@@ -142,8 +142,7 @@ void dns_cache_data_free(struct dns_cache_data *data)
 	free(data);
 }
 
-struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr,
-											   int addr_len)
+struct dns_cache_data *dns_cache_new_data(void)
 {
 	struct dns_cache_addr *cache_addr = malloc(sizeof(struct dns_cache_addr));
 	memset(cache_addr, 0, sizeof(struct dns_cache_addr));
@@ -151,6 +150,50 @@ struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname,
 		return NULL;
 	}
 
+	cache_addr->head.cache_type = CACHE_TYPE_NONE;
+	cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
+
+	return (struct dns_cache_data *)cache_addr;
+}
+
+void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl)
+{
+	if (dns_cache == NULL) {
+		goto errout;
+	}
+
+	struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache;
+	if (cache_addr == NULL) {
+		goto errout;
+	}
+
+	memset(cache_addr->addr_data.addr, 0, sizeof(cache_addr->addr_data.addr));
+
+	if (cname) {
+		safe_strncpy(cache_addr->addr_data.cname, cname, DNS_MAX_CNAME_LEN);
+		cache_addr->addr_data.cname_ttl = cname_ttl;
+	}
+
+	cache_addr->head.cache_flag = cache_flag;
+	cache_addr->addr_data.soa = 1;
+	cache_addr->head.cache_type = CACHE_TYPE_ADDR;
+	cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
+errout:
+	return;
+}
+
+void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
+							 unsigned char *addr, int addr_len)
+{
+	if (dns_cache == NULL) {
+		goto errout;
+	}
+
+	struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache;
+	if (cache_addr == NULL) {
+		goto errout;
+	}
+
 	if (addr_len == DNS_RR_A_LEN) {
 		memcpy(cache_addr->addr_data.addr, addr, DNS_RR_A_LEN);
 	} else if (addr_len != DNS_RR_AAAA_LEN) {
@@ -167,16 +210,8 @@ struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname,
 	cache_addr->head.cache_flag = cache_flag;
 	cache_addr->head.cache_type = CACHE_TYPE_ADDR;
 	cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
-
-	return (struct dns_cache_data *)cache_addr;
-
 errout:
-	if (cache_addr) {
-		free(cache_addr);
-		cache_addr = NULL;
-	}
-
-	return NULL;
+	return;
 }
 
 struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len)
@@ -377,6 +412,18 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
 	return ttl;
 }
 
+int dns_cache_is_soa(struct dns_cache *dns_cache) {
+	if (dns_cache == NULL) {
+		return 0;
+	}
+
+	struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache_get_data(dns_cache);
+	if (cache_addr->addr_data.soa) {
+		return 1;
+	}
+	return 0;
+}
+
 struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache)
 {
 	return dns_cache->cache_data;
@@ -468,7 +515,7 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
 		}
 
 		if (ttl < 0) {
-			if (dns_cache_head.enable_inactive) {
+			if (dns_cache_head.enable_inactive && (dns_cache_is_soa(dns_cache) == 0)) {
 				_dns_cache_move_inactive(dns_cache);
 			} else {
 				_dns_cache_remove(dns_cache);

+ 10 - 3
src/dns_cache.h

@@ -63,6 +63,7 @@ struct dns_cache_addr {
 	struct dns_cache_addr_data {
 		unsigned int cname_ttl;
 		char cname[DNS_MAX_CNAME_LEN];
+		char soa;
 		union {
 			unsigned char ipv4_addr[DNS_RR_A_LEN];
 			unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
@@ -116,9 +117,6 @@ uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data);
 
 void dns_cache_data_free(struct dns_cache_data *data);
 
-struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr,
-											   int addr_len);
-
 struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len);
 
 int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
@@ -145,8 +143,17 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre);
 
 int dns_cache_get_ttl(struct dns_cache *dns_cache);
 
+int dns_cache_is_soa(struct dns_cache *dns_cache);
+
+struct dns_cache_data *dns_cache_new_data(void);
+
 struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache);
 
+void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
+							 unsigned char *addr, int addr_len);
+
+void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl);
+
 void dns_cache_destroy(void);
 
 int dns_cache_load(const char *file);

+ 50 - 31
src/dns_server.c

@@ -736,6 +736,10 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
 		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) {
@@ -759,7 +763,7 @@ errout:
 static int _dns_server_request_complete_A(struct dns_request *request)
 {
 	char *cname = NULL;
-	int cname_ttl = 0;
+	int cname_ttl = dns_conf_rr_ttl;
 	struct dns_cache_data *cache_data = NULL;
 
 	if (request->has_cname) {
@@ -767,27 +771,29 @@ static int _dns_server_request_complete_A(struct dns_request *request)
 		cname_ttl = request->ttl_cname;
 	}
 
-	if (request->has_ipv4 == 0) {
-		return 0;
+	cache_data = dns_cache_new_data();
+	if (cache_data == NULL) {
+		goto errout;
 	}
 
-	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 (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]);
 
-	request->has_soa = 0;
-	if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
-		request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
+		request->has_soa = 0;
+		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 {
+		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;
 	}
 
-	cache_data = dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_RR_A_LEN);
-	if (cache_data == NULL) {
-		goto errout;
-	}
-
 	if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
 		goto errout;
 	}
@@ -807,7 +813,7 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
 {
 	int ret = -1;
 	char *cname = NULL;
-	int cname_ttl = 0;
+	int cname_ttl = dns_conf_rr_ttl;
 	struct dns_cache_data *cache_data = NULL;
 
 	if (request->has_cname) {
@@ -815,6 +821,11 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
 		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",
@@ -829,20 +840,22 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
 		}
 
 		/* if doing prefetch, update cache only */
-		if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
-			cache_data =
-				dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv6_addr, DNS_T_AAAA);
-			if (cache_data == NULL) {
-				goto errout;
-			}
-
-			if (_dns_server_request_update_cache(request, DNS_T_AAAA, cache_data) != 0) {
-				goto errout;
-			}
-			cache_data = NULL;
-		}
+		dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv6_addr,
+								DNS_T_AAAA);
 
 		request->has_soa = 0;
+	} else {
+		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)) {
@@ -854,12 +867,13 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
 			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_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_T_A);
+				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;
 				}
@@ -2417,7 +2431,7 @@ static int _dns_server_process_cache(struct dns_request *request)
 	if (dns_cache == NULL) {
 		if (request->dualstack_selection && request->qtype == DNS_T_AAAA) {
 			dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A);
-			if (dns_cache_A) {
+			if (dns_cache_A && dns_cache_is_soa(dns_cache_A) == 0 && dns_cache_is_soa(dns_cache)) {
 				tlog(TLOG_DEBUG, "No IPV6 Found, Force IPV4 perfered.");
 				if (dns_cache_get_ttl(dns_cache_A) == 0) {
 					uint32_t server_flags = request->server_flags;
@@ -2437,6 +2451,13 @@ static int _dns_server_process_cache(struct dns_request *request)
 		goto out;
 	}
 
+	if (request->qtype == DNS_T_A) {
+		if (dns_cache_is_soa(dns_cache)) {
+			ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
+			goto out;
+		}
+	}
+
 	if (request->dualstack_selection && request->qtype == DNS_T_AAAA) {
 		dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A);
 		if (dns_cache_A && (dns_cache_A->info.speed > 0)) {
@@ -2610,8 +2631,6 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain,
 
 	_dns_server_set_dualstack_selection(request);
 
-	tlog(TLOG_DEBUG, "dualstack selection %d", request->dualstack_selection);
-
 	if (_dns_server_process_special_query(request) == 0) {
 		goto clean_exit;
 	}