浏览代码

feature: support response mode: first-ping, fastest-ip, fastest-response

Nick Peng 3 年之前
父节点
当前提交
ab415f2ee9
共有 9 个文件被更改,包括 195 次插入34 次删除
  1. 5 1
      etc/smartdns/smartdns.conf
  2. 1 1
      src/dns_cache.h
  3. 6 1
      src/dns_client.c
  4. 16 1
      src/dns_conf.c
  5. 6 0
      src/dns_conf.h
  6. 114 28
      src/dns_server.c
  7. 21 0
      src/include/conf.h
  8. 25 1
      src/lib/conf.c
  9. 1 1
      src/smartdns.c

+ 5 - 1
etc/smartdns/smartdns.conf

@@ -109,7 +109,7 @@ cache-size 16384
 # rr-ttl: ttl for all record
 # rr-ttl: ttl for all record
 # rr-ttl-min: minimum ttl for resource record
 # rr-ttl-min: minimum ttl for resource record
 # rr-ttl-max: maximum ttl for resource record
 # rr-ttl-max: maximum ttl for resource record
-# tr-ttl-reply-max: maximum reply ttl for resource record
+# rr-ttl-reply-max: maximum reply ttl for resource record
 # example:
 # example:
 # rr-ttl 300
 # rr-ttl 300
 # rr-ttl-min 60
 # rr-ttl-min 60
@@ -120,6 +120,10 @@ cache-size 16384
 # example:
 # example:
 # max-reply-ip-num 1
 # max-reply-ip-num 1
 
 
+# response mode
+# Experimental feature
+# response-mode [first-ping|fastest-ip|fastest-response]
+
 # set log level
 # set log level
 # log-level: [level], level=fatal, error, warn, notice, info, debug
 # log-level: [level], level=fatal, error, warn, notice, info, debug
 # log-file: file path of log file.
 # log-file: file path of log file.

+ 1 - 1
src/dns_cache.h

@@ -31,7 +31,7 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#define DNS_CACHE_TTL_MIN 30
+#define DNS_CACHE_TTL_MIN 1
 #define DNS_CACHE_VERSION_LEN 32
 #define DNS_CACHE_VERSION_LEN 32
 #define MAGIC_NUMBER 0x6548634163536e44
 #define MAGIC_NUMBER 0x6548634163536e44
 #define MAGIC_CACHE_DATA 0x44615461
 #define MAGIC_CACHE_DATA 0x44615461

+ 6 - 1
src/dns_client.c

@@ -1988,6 +1988,11 @@ static int _dns_client_socket_ssl_send(struct dns_server_info *server, const voi
 		return -1;
 		return -1;
 	}
 	}
 
 
+	if (num < 0) {
+		errno = EINVAL;
+		return -1;
+	}
+
 	ret = _ssl_write(server, buf, num);
 	ret = _ssl_write(server, buf, num);
 	if (ret > 0) {
 	if (ret > 0) {
 		return ret;
 		return ret;
@@ -2075,7 +2080,7 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
 			return 0;
 			return 0;
 		}
 		}
 
 
-		tlog(TLOG_ERROR, "SSL read fail error no: %s(%lx)\n", ERR_reason_error_string(ssl_err), ssl_err);
+		tlog(TLOG_INFO, "SSL read fail error no: %s(%lx), len: %d\n", ERR_reason_error_string(ssl_err), ssl_err, num);
 		errno = EFAULT;
 		errno = EFAULT;
 		ret = -1;
 		ret = -1;
 		break;
 		break;

+ 16 - 1
src/dns_conf.c

@@ -59,6 +59,14 @@ int dns_conf_tcp_idle_time = 120;
 
 
 int dns_conf_max_reply_ip_num = DNS_MAX_REPLY_IP_NUM;
 int dns_conf_max_reply_ip_num = DNS_MAX_REPLY_IP_NUM;
 
 
+static struct config_enum_list dns_conf_response_mode_enum[] = {
+	{"first-ping", DNS_RESPONSE_MODE_FIRST_PING_IP},
+	{"fastest-ip", DNS_RESPONSE_MODE_FASTEST_IP},
+	{"fastest-response", DNS_RESPONSE_MODE_FASTEST_RESPONSE},
+	{0, 0}};
+
+enum response_mode_type dns_conf_response_mode;
+
 /* cache */
 /* cache */
 int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
 int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
 int dns_conf_prefetch = 0;
 int dns_conf_prefetch = 0;
@@ -1022,7 +1030,7 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
 	bind_ip->flags = server_flag;
 	bind_ip->flags = server_flag;
 	bind_ip->group = group;
 	bind_ip->group = group;
 	dns_conf_bind_ip_num++;
 	dns_conf_bind_ip_num++;
-	tlog(TLOG_DEBUG, "bind ip %s, type:%d, flag: %X", ip, type, server_flag);
+	tlog(TLOG_DEBUG, "bind ip %s, type: %d, flag: %X", ip, type, server_flag);
 
 
 	return 0;
 	return 0;
 
 
@@ -1897,6 +1905,7 @@ static struct config_item _config_item[] = {
 	CONF_INT("rr-ttl-max", &dns_conf_rr_ttl_max, 0, CONF_INT_MAX),
 	CONF_INT("rr-ttl-max", &dns_conf_rr_ttl_max, 0, CONF_INT_MAX),
 	CONF_INT("rr-ttl-reply-max", &dns_conf_rr_ttl_reply_max, 0, CONF_INT_MAX),
 	CONF_INT("rr-ttl-reply-max", &dns_conf_rr_ttl_reply_max, 0, CONF_INT_MAX),
 	CONF_INT("max-reply-ip-num", &dns_conf_max_reply_ip_num, 1, CONF_INT_MAX),
 	CONF_INT("max-reply-ip-num", &dns_conf_max_reply_ip_num, 1, CONF_INT_MAX),
+	CONF_ENUM("response-mode", &dns_conf_response_mode, &dns_conf_response_mode_enum),
 	CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
 	CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
 	CONF_YESNO("force-no-CNAME", &dns_conf_force_no_cname),
 	CONF_YESNO("force-no-CNAME", &dns_conf_force_no_cname),
 	CONF_CUSTOM("force-qtype-SOA", _config_qtype_soa, NULL),
 	CONF_CUSTOM("force-qtype-SOA", _config_qtype_soa, NULL),
@@ -2069,6 +2078,12 @@ static int _dns_conf_load_post(void)
 {
 {
 	_dns_conf_speed_check_mode_verify();
 	_dns_conf_speed_check_mode_verify();
 
 
+	if (dns_conf_cachesize == 0 && dns_conf_response_mode == DNS_RESPONSE_MODE_FASTEST_RESPONSE) {
+		dns_conf_response_mode = DNS_RESPONSE_MODE_FASTEST_IP;
+		tlog(TLOG_WARN, "force set response to %s as cache size is 0",
+			 dns_conf_response_mode_enum[dns_conf_response_mode].name);
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 6 - 0
src/dns_conf.h

@@ -298,6 +298,12 @@ extern int dns_conf_dualstack_ip_allow_force_AAAA;
 extern int dns_conf_dualstack_ip_selection_threshold;
 extern int dns_conf_dualstack_ip_selection_threshold;
 
 
 extern int dns_conf_max_reply_ip_num;
 extern int dns_conf_max_reply_ip_num;
+enum response_mode_type {
+	DNS_RESPONSE_MODE_FIRST_PING_IP = 0,
+	DNS_RESPONSE_MODE_FASTEST_IP,
+	DNS_RESPONSE_MODE_FASTEST_RESPONSE,
+};
+extern enum response_mode_type dns_conf_response_mode;
 
 
 extern int dns_conf_rr_ttl;
 extern int dns_conf_rr_ttl;
 extern int dns_conf_rr_ttl_reply_max;
 extern int dns_conf_rr_ttl_reply_max;

+ 114 - 28
src/dns_server.c

@@ -110,6 +110,8 @@ struct dns_server_post_context {
 	int do_ipset;
 	int do_ipset;
 	int do_log_result;
 	int do_log_result;
 	int reply_ttl;
 	int reply_ttl;
+	int cache_ttl;
+	int no_check_add_ip;
 	int do_audit;
 	int do_audit;
 	int do_force_soa;
 	int do_force_soa;
 	int skip_notify_count;
 	int skip_notify_count;
@@ -477,6 +479,11 @@ static void _dns_server_audit_log(struct dns_server_post_context *context)
 					continue;
 					continue;
 				}
 				}
 
 
+				if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
+					strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
+					continue;
+				}
+
 				const char *fmt = "%d.%d.%d.%d";
 				const char *fmt = "%d.%d.%d.%d";
 				if (ip_num > 0) {
 				if (ip_num > 0) {
 					fmt = ", %d.%d.%d.%d";
 					fmt = ", %d.%d.%d.%d";
@@ -492,6 +499,12 @@ static void _dns_server_audit_log(struct dns_server_post_context *context)
 				if (dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, ipv6_addr) != 0) {
 				if (dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, ipv6_addr) != 0) {
 					continue;
 					continue;
 				}
 				}
+
+				if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
+					strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
+					continue;
+				}
+
 				const char *fmt = "%s";
 				const char *fmt = "%s";
 				if (ip_num > 0) {
 				if (ip_num > 0) {
 					fmt = ", %s";
 					fmt = ", %s";
@@ -543,8 +556,9 @@ static void _dns_server_audit_log(struct dns_server_post_context *context)
 	snprintf(req_time, sizeof(req_time), "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d]", tm.year, tm.mon, tm.mday, tm.hour,
 	snprintf(req_time, sizeof(req_time), "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d]", tm.year, tm.mon, tm.mday, tm.hour,
 			 tm.min, tm.sec, tm.usec / 1000);
 			 tm.min, tm.sec, tm.usec / 1000);
 
 
-	tlog_printf(dns_audit, "%s %s query %s, time %lums, type %d, result %s\n", req_time, req_host, request->domain,
-				get_tick_count() - request->send_tick, request->qtype, req_result);
+	tlog_printf(dns_audit, "%s %s query %s, type %d, time %lums, speed: %.1fms, result %s\n", req_time, req_host,
+				request->domain, request->qtype, get_tick_count() - request->send_tick, ((float)request->ping_time) / 10,
+				req_result);
 }
 }
 
 
 static void _dns_rrs_result_log(struct dns_server_post_context *context, struct dns_ip_address *addr_map)
 static void _dns_rrs_result_log(struct dns_server_post_context *context, struct dns_ip_address *addr_map)
@@ -909,7 +923,7 @@ static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpac
 }
 }
 
 
 static int _dns_server_request_update_cache(struct dns_request *request, dns_type_t qtype,
 static int _dns_server_request_update_cache(struct dns_request *request, dns_type_t qtype,
-											struct dns_cache_data *cache_data, int has_soa)
+											struct dns_cache_data *cache_data, int has_soa, int cache_ttl)
 {
 {
 	int ttl = 0;
 	int ttl = 0;
 	int speed = 0;
 	int speed = 0;
@@ -918,7 +932,11 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
 		goto errout;
 		goto errout;
 	}
 	}
 
 
-	ttl = _dns_server_get_conf_ttl(request->ip_ttl);
+	if (cache_ttl > 0) {
+		ttl = cache_ttl;
+	} else {
+		ttl = _dns_server_get_conf_ttl(request->ip_ttl);
+	}
 	speed = request->ping_time;
 	speed = request->ping_time;
 
 
 	if (has_soa) {
 	if (has_soa) {
@@ -926,11 +944,14 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
 			ttl = _dns_server_get_conf_ttl(request->ip_ttl);
 			ttl = _dns_server_get_conf_ttl(request->ip_ttl);
 		} else {
 		} else {
 			ttl = dns_conf_rr_ttl;
 			ttl = dns_conf_rr_ttl;
+			if (ttl == 0) {
+				ttl = DNS_SERVER_TMOUT_TTL;
+			}
 		}
 		}
 		dns_cache_set_data_soa(cache_data, request->server_flags, request->cname, request->ttl_cname);
 		dns_cache_set_data_soa(cache_data, request->server_flags, request->cname, request->ttl_cname);
 	}
 	}
 
 
-	tlog(TLOG_DEBUG, "cache %s qtype:%d ttl: %d\n", request->domain, qtype, ttl);
+	tlog(TLOG_DEBUG, "cache %s qtype: %d ttl: %d\n", request->domain, qtype, ttl);
 
 
 	/* if doing prefetch, update cache only */
 	/* if doing prefetch, update cache only */
 	if (request->prefetch) {
 	if (request->prefetch) {
@@ -1006,6 +1027,10 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
 					continue;
 					continue;
 				}
 				}
 
 
+				if (strncmp(request->cname, name, DNS_MAX_CNAME_LEN - 1) != 0) {
+					continue;
+				}
+
 				ret = dns_add_A(cname_packet, DNS_RRS_AN, request->cname, ttl, ipv4_addr);
 				ret = dns_add_A(cname_packet, DNS_RRS_AN, request->cname, ttl, ipv4_addr);
 				if (ret != 0) {
 				if (ret != 0) {
 					return -1;
 					return -1;
@@ -1018,6 +1043,10 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
 					continue;
 					continue;
 				}
 				}
 
 
+				if (strncmp(request->cname, name, DNS_MAX_CNAME_LEN - 1) != 0) {
+					continue;
+				}
+
 				ret = dns_add_AAAA(cname_packet, DNS_RRS_AN, request->cname, ttl, ipv6_addr);
 				ret = dns_add_AAAA(cname_packet, DNS_RRS_AN, request->cname, ttl, ipv6_addr);
 				if (ret != 0) {
 				if (ret != 0) {
 					return -1;
 					return -1;
@@ -1234,7 +1263,7 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
 		has_soa = 0;
 		has_soa = 0;
 	}
 	}
 
 
-	if (_dns_server_request_update_cache(request, context->qtype, cache_packet, has_soa) != 0) {
+	if (_dns_server_request_update_cache(request, context->qtype, cache_packet, has_soa, context->cache_ttl) != 0) {
 		tlog(TLOG_WARN, "update packet cache failed.");
 		tlog(TLOG_WARN, "update packet cache failed.");
 	}
 	}
 
 
@@ -1937,6 +1966,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
 	int may_complete = 0;
 	int may_complete = 0;
 	int threshold = 100;
 	int threshold = 100;
 	struct dns_ip_address *addr_map = NULL;
 	struct dns_ip_address *addr_map = NULL;
+	int last_rtt = request->ping_time;
 
 
 	if (request == NULL) {
 	if (request == NULL) {
 		return;
 		return;
@@ -1948,6 +1978,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
 		return;
 		return;
 	} else if (result == PING_RESULT_TIMEOUT) {
 	} else if (result == PING_RESULT_TIMEOUT) {
 		tlog(TLOG_DEBUG, "ping %s timeout", host);
 		tlog(TLOG_DEBUG, "ping %s timeout", host);
+		goto out;
 		return;
 		return;
 	} else if (result == PING_RESULT_ERROR) {
 	} else if (result == PING_RESULT_ERROR) {
 		if (addr->sa_family != AF_INET6) {
 		if (addr->sa_family != AF_INET6) {
@@ -1965,7 +1996,6 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
 	}
 	}
 
 
 	int rtt = tv->tv_sec * 10000 + tv->tv_usec / 100;
 	int rtt = tv->tv_sec * 10000 + tv->tv_usec / 100;
-	int last_rtt = request->ping_time;
 
 
 	if (result == PING_RESULT_RESPONSE) {
 	if (result == PING_RESULT_RESPONSE) {
 		tlog(TLOG_DEBUG, "from %s: seq=%d time=%d, lasttime=%d id=%d", host, seqno, rtt, last_rtt, request->id);
 		tlog(TLOG_DEBUG, "from %s: seq=%d time=%d, lasttime=%d id=%d", host, seqno, rtt, last_rtt, request->id);
@@ -2058,10 +2088,18 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
 		break;
 		break;
 	}
 	}
 
 
+out:
 	/* If the ping delay is less than the threshold, the result is returned */
 	/* If the ping delay is less than the threshold, the result is returned */
-	if (rtt < threshold) {
-		may_complete = 1;
-	} else if (rtt < (int)(get_tick_count() - request->send_tick) * 8) {
+	if (request->ping_time > 0) {
+		if (request->ping_time < threshold) {
+			may_complete = 1;
+		} else if (request->ping_time < (int)(get_tick_count() - request->send_tick) * 8) {
+			may_complete = 1;
+		}
+	}
+
+	/* Get first ping result */
+	if (dns_conf_response_mode == DNS_RESPONSE_MODE_FIRST_PING_IP && last_rtt == -1 && request->ping_time > 0) {
 		may_complete = 1;
 		may_complete = 1;
 	}
 	}
 
 
@@ -2204,8 +2242,8 @@ static int _dns_server_is_adblock_ipv6(const unsigned char addr[16])
 	return -1;
 	return -1;
 }
 }
 
 
-static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request *request, const char *domain, char *cname,
-										unsigned int result_flag)
+static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
+										char *cname, unsigned int result_flag)
 {
 {
 	int ttl = 0;
 	int ttl = 0;
 	int ip_check_result = 0;
 	int ip_check_result = 0;
@@ -2282,8 +2320,8 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
 	return 0;
 	return 0;
 }
 }
 
 
-static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_request *request, const char *domain, char *cname,
-										   unsigned int result_flag)
+static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
+										   char *cname, unsigned int result_flag)
 {
 {
 	unsigned char addr[16];
 	unsigned char addr[16];
 	char name[DNS_MAX_CNAME_LEN] = {0};
 	char name[DNS_MAX_CNAME_LEN] = {0};
@@ -2408,10 +2446,17 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
 			case DNS_T_NS: {
 			case DNS_T_NS: {
 				char nsname[DNS_MAX_CNAME_LEN];
 				char nsname[DNS_MAX_CNAME_LEN];
 				dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, nsname, DNS_MAX_CNAME_LEN);
 				dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, nsname, DNS_MAX_CNAME_LEN);
-				tlog(TLOG_DEBUG, "NS: %s ttl:%d nsname: %s\n", name, ttl, nsname);
+				tlog(TLOG_DEBUG, "NS: %s ttl: %d nsname: %s\n", name, ttl, nsname);
 			} break;
 			} break;
 			case DNS_T_CNAME: {
 			case DNS_T_CNAME: {
-				dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
+				char domain_name[DNS_MAX_CNAME_LEN] = {0};
+				char domain_cname[DNS_MAX_CNAME_LEN] = {0};
+				dns_get_CNAME(rrs, domain_name, DNS_MAX_CNAME_LEN, &ttl, domain_cname, DNS_MAX_CNAME_LEN);
+				if (strncmp(domain_name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
+					strncmp(domain_name, cname, DNS_MAX_CNAME_LEN - 1) != 0) {
+					continue;
+				}
+				safe_strncpy(cname, domain_cname, DNS_MAX_CNAME_LEN);
 				tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname);
 				tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname);
 			} break;
 			} break;
 			case DNS_T_SOA: {
 			case DNS_T_SOA: {
@@ -2440,8 +2485,8 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
 	return 0;
 	return 0;
 }
 }
 
 
-static int _dns_server_passthrough_rule_check(struct dns_request *request, const char *domain, struct dns_packet *packet,
-											  unsigned int result_flag, int *pttl)
+static int _dns_server_passthrough_rule_check(struct dns_request *request, const char *domain,
+											  struct dns_packet *packet, unsigned int result_flag, int *pttl)
 {
 {
 	int ttl = 0;
 	int ttl = 0;
 	char name[DNS_MAX_CNAME_LEN] = {0};
 	char name[DNS_MAX_CNAME_LEN] = {0};
@@ -2486,7 +2531,7 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
 					continue;
 					continue;
 				}
 				}
 
 
-				tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl_tmp, addr[0], addr[1], addr[2],
+				tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %d.%d.%d.%d", name, ttl_tmp, addr[0], addr[1], addr[2],
 					 addr[3]);
 					 addr[3]);
 
 
 				/* ip rule check */
 				/* ip rule check */
@@ -2575,7 +2620,13 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
 
 
 				/* get A result */
 				/* get A result */
 				dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
 				dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
-				if (_dns_ip_address_check_add(request, name, addr, DNS_T_A) != 0) {
+
+				if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
+					strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
+					continue;
+				}
+
+				if (context->no_check_add_ip == 0 && _dns_ip_address_check_add(request, name, addr, DNS_T_A) != 0) {
 					continue;
 					continue;
 				}
 				}
 
 
@@ -2599,7 +2650,13 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
 					continue;
 					continue;
 				}
 				}
 				dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
 				dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
-				if (_dns_ip_address_check_add(request, name, addr, DNS_T_AAAA) != 0) {
+
+				if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
+					strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
+					continue;
+				}
+
+				if (context->no_check_add_ip == 0 && _dns_ip_address_check_add(request, name, addr, DNS_T_AAAA) != 0) {
 					continue;
 					continue;
 				}
 				}
 
 
@@ -2617,7 +2674,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
 				char cname[DNS_MAX_CNAME_LEN];
 				char cname[DNS_MAX_CNAME_LEN];
 				char name[DNS_MAX_CNAME_LEN] = {0};
 				char name[DNS_MAX_CNAME_LEN] = {0};
 				dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
 				dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
-				tlog(TLOG_DEBUG, "NS: %s ttl:%d cname: %s\n", name, ttl, cname);
+				tlog(TLOG_DEBUG, "NS: %s ttl: %d cname: %s\n", name, ttl, cname);
 			} break;
 			} break;
 			case DNS_T_CNAME: {
 			case DNS_T_CNAME: {
 				char cname[DNS_MAX_CNAME_LEN];
 				char cname[DNS_MAX_CNAME_LEN];
@@ -2627,7 +2684,12 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
 				}
 				}
 
 
 				dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
 				dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
-				tlog(TLOG_DEBUG, "name:%s ttl: %d cname: %s\n", name, ttl, cname);
+				tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname);
+				if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
+					strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
+					continue;
+				}
+
 				safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
 				safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
 				request->ttl_cname = _dns_server_get_conf_ttl(ttl);
 				request->ttl_cname = _dns_server_get_conf_ttl(ttl);
 				request->has_cname = 1;
 				request->has_cname = 1;
@@ -2644,9 +2706,6 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
 					 "%d, minimum: %d",
 					 "%d, minimum: %d",
 					 request->domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial,
 					 request->domain, 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.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
-				if (atomic_inc_return(&request->soa_num) >= (dns_server_num() / 2)) {
-					_dns_server_request_complete(request);
-				}
 			} break;
 			} break;
 			default:
 			default:
 				break;
 				break;
@@ -2754,10 +2813,10 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
 	}
 	}
 
 
 	if (rtype == DNS_QUERY_RESULT) {
 	if (rtype == DNS_QUERY_RESULT) {
-		tlog(TLOG_DEBUG, "query result from server %s:%d, type: %d", dns_client_get_server_ip(server_info),
+		tlog(TLOG_DEBUG, "query result from server %s: %d, type: %d", dns_client_get_server_ip(server_info),
 			 dns_client_get_server_port(server_info), dns_client_get_server_type(server_info));
 			 dns_client_get_server_port(server_info), dns_client_get_server_type(server_info));
 
 
-		if (request->passthrough) {
+		if (request->passthrough && atomic_read(&request->notified) == 0) {
 			struct dns_server_post_context context;
 			struct dns_server_post_context context;
 			int ttl = 0;
 			int ttl = 0;
 			ret = _dns_server_passthrough_rule_check(request, domain, packet, result_flag, &ttl);
 			ret = _dns_server_passthrough_rule_check(request, domain, packet, result_flag, &ttl);
@@ -2778,6 +2837,33 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
 			context.reply_ttl = ttl;
 			context.reply_ttl = ttl;
 			return _dns_server_reply_passthrouth(&context);
 			return _dns_server_reply_passthrouth(&context);
 		}
 		}
+
+		if (request->prefetch == 0 && dns_conf_response_mode == DNS_RESPONSE_MODE_FASTEST_RESPONSE &&
+			atomic_read(&request->notified) == 0) {
+			struct dns_server_post_context context;
+			int ttl = 0;
+			ret = _dns_server_passthrough_rule_check(request, domain, packet, result_flag, &ttl);
+			if (ret != 0) {
+				_dns_server_post_context_init_from(&context, request, packet, inpacket, inpacket_len);
+				context.do_cache = 1;
+				context.do_audit = 1;
+				context.do_reply = 1;
+				context.do_ipset = 1;
+				context.reply_ttl = 2;
+				context.cache_ttl = 2;
+				context.no_check_add_ip = 1;
+				_dns_server_reply_passthrouth(&context);
+				request->cname[0] = 0;
+				request->has_ip = 0;
+				request->has_cname = 0;
+				request->has_ping_result = 0;
+				request->has_soa = 0;
+				request->has_ptr = 0;
+				request->ping_time = -1;
+				request->ip_ttl = 0;
+			}
+		}
+
 		_dns_server_process_answer(request, domain, packet, result_flag);
 		_dns_server_process_answer(request, domain, packet, result_flag);
 		return 0;
 		return 0;
 	} else if (rtype == DNS_QUERY_ERR) {
 	} else if (rtype == DNS_QUERY_ERR) {

+ 21 - 0
src/include/conf.h

@@ -64,6 +64,16 @@ struct config_item_size {
 	size_t max;
 	size_t max;
 };
 };
 
 
+struct config_enum_list {
+	char *name;
+	int id;
+};
+
+struct config_enum {
+	int *data;
+	struct config_enum_list *list;
+};
+
 #define CONF_INT(key, value, min_value, max_value)                                                                     \
 #define CONF_INT(key, value, min_value, max_value)                                                                     \
 	{                                                                                                                  \
 	{                                                                                                                  \
 		key, conf_int, &(struct config_item_int)                                                                       \
 		key, conf_int, &(struct config_item_int)                                                                       \
@@ -92,6 +102,15 @@ struct config_item_size {
 			.data = value, .min = min_value, .max = max_value                                                          \
 			.data = value, .min = min_value, .max = max_value                                                          \
 		}                                                                                                              \
 		}                                                                                                              \
 	}
 	}
+
+#define CONF_ENUM(key, value, enum)                                                                                    \
+	{                                                                                                                  \
+		key, conf_enum, &(struct config_enum)                                                                          \
+		{                                                                                                              \
+			.data = (int *)value, .list = (struct config_enum_list *)enum                                              \
+		}                                                                                                              \
+	}
+
 /*
 /*
  * func: int (*func)(void *data, int argc, char *argv[]);
  * func: int (*func)(void *data, int argc, char *argv[]);
  */
  */
@@ -118,6 +137,8 @@ extern int conf_yesno(const char *item, void *data, int argc, char *argv[]);
 
 
 extern int conf_size(const char *item, void *data, int argc, char *argv[]);
 extern int conf_size(const char *item, void *data, int argc, char *argv[]);
 
 
+extern int conf_enum(const char *item, void *data, int argc, char *argv[]);
+
 /*
 /*
  * Example:
  * Example:
  *  int num = 0;
  *  int num = 0;

+ 25 - 1
src/lib/conf.c

@@ -97,7 +97,6 @@ int conf_yesno(const char *item, void *data, int argc, char *argv[])
 
 
 int conf_size(const char *item, void *data, int argc, char *argv[])
 int conf_size(const char *item, void *data, int argc, char *argv[])
 {
 {
-	/* read dns cache size */
 	int base = 1;
 	int base = 1;
 	size_t size = 0;
 	size_t size = 0;
 	int num = 0;
 	int num = 0;
@@ -129,6 +128,31 @@ int conf_size(const char *item, void *data, int argc, char *argv[])
 	return 0;
 	return 0;
 }
 }
 
 
+int conf_enum(const char *item, void *data, int argc, char *argv[])
+{
+	struct config_enum *item_enum = data;
+	char *enum_name = argv[1];
+	int i = 0;
+
+	if (argc <= 0) {
+		return -1;
+	}
+
+	for (i = 0; item_enum->list[i].name != NULL; i++) {
+		if (strcmp(enum_name, item_enum->list[i].name) == 0) {
+			*(item_enum->data) = item_enum->list[i].id;
+			return 0;
+		}
+	}
+
+	printf("Not found config value '%s', valid value is:\n", enum_name);
+	for (i = 0; item_enum->list[i].name != NULL; i++) {
+		printf(" %s\n", item_enum->list[i].name);
+	}
+
+	return -1;
+}
+
 static void conf_getopt_reset(void)
 static void conf_getopt_reset(void)
 {
 {
 	static struct option long_options[] = {{"-", 0, 0, 0}, {0, 0, 0, 0}};
 	static struct option long_options[] = {{"-", 0, 0, 0}, {0, 0, 0, 0}};

+ 1 - 1
src/smartdns.c

@@ -348,7 +348,7 @@ static int _smartdns_init(void)
 	tlog_setlogscreen(verbose_screen);
 	tlog_setlogscreen(verbose_screen);
 	tlog_setlevel(dns_conf_log_level);
 	tlog_setlevel(dns_conf_log_level);
 
 
-	tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <[email protected]>, build:%s %s)", __DATE__,
+	tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <[email protected]>, build: %s %s)", __DATE__,
 		 __TIME__);
 		 __TIME__);
 
 
 	if (_smartdns_init_ssl() != 0) {
 	if (_smartdns_init_ssl() != 0) {