فهرست منبع

feature: add acl-enable option.

Nick Peng 2 سال پیش
والد
کامیت
2d6779fc87
5فایلهای تغییر یافته به همراه258 افزوده شده و 100 حذف شده
  1. 81 68
      src/dns_conf.c
  2. 18 13
      src/dns_conf.h
  3. 45 17
      src/dns_server.c
  4. 44 0
      test/cases/test-client-rule.cc
  5. 70 2
      test/cases/test-group.cc

+ 81 - 68
src/dns_conf.c

@@ -146,14 +146,13 @@ int dns_conf_audit_syslog;
 struct dns_conf_group_info {
 	struct list_head list;
 	const char *group_name;
-	struct dns_conf_doamin_rule_group *domain_rule;
+	struct dns_conf_group *rule;
 };
 struct dns_conf_group_info *dns_conf_current_group_info;
 struct dns_conf_group_info *dns_conf_default_group_info;
 static LIST_HEAD(dns_conf_group_info_list);
 
-struct dns_conf_domain_rule dns_conf_domain_rule;
-struct dns_conf_address_rule dns_conf_address_rule;
+struct dns_conf_rule dns_conf_rule;
 struct dns_conf_client_rule dns_conf_client_rule;
 
 /* dual-stack selection */
@@ -179,6 +178,7 @@ struct dns_nftset_names dns_conf_nftset_no_speed;
 struct dns_nftset_names dns_conf_nftset;
 int dns_conf_nftset_debug_enable;
 int dns_conf_mdns_lookup;
+int dns_conf_acl_enable;
 
 char dns_conf_user[DNS_CONF_USERNAME_LEN];
 
@@ -208,8 +208,10 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address);
 static struct dns_domain_rule *_config_domain_rule_get(const char *domain);
 typedef int (*set_rule_add_func)(const char *value, void *priv);
 static int _config_ip_rule_set_each(const char *ip_set, set_rule_add_func callback, void *priv);
-static struct dns_conf_doamin_rule_group *_config_domain_rule_group_get(const char *group_name);
-static struct dns_conf_doamin_rule_group *_config_domain_rule_group_new(const char *group_name);
+static struct dns_conf_group *_config_rule_group_get(const char *group_name);
+static struct dns_conf_group *_config_rule_group_new(const char *group_name);
+static struct dns_conf_group *_config_current_rule_group(void);
+static void _config_ip_iter_free(radix_node_t *node, void *cbctx);
 
 static void *_new_dns_rule_ext(enum domain_rule domain_rule, int ext_size)
 {
@@ -455,6 +457,15 @@ struct dns_proxy_names *dns_server_get_proxy_nams(const char *proxyname)
 	return NULL;
 }
 
+static struct dns_conf_group *_config_current_rule_group(void)
+{
+	if (dns_conf_current_group_info == NULL) {
+		return NULL;
+	}
+
+	return dns_conf_current_group_info->rule;
+}
+
 static struct dns_conf_group_info *_config_current_group(void)
 {
 	return dns_conf_current_group_info;
@@ -489,7 +500,7 @@ static void _config_current_group_pop(void)
 static int _config_current_group_push(const char *group_name)
 {
 	struct dns_conf_group_info *group_info = NULL;
-	struct dns_conf_doamin_rule_group *domain_rule = NULL;
+	struct dns_conf_group *group_rule = NULL;
 
 	group_info = malloc(sizeof(*group_info));
 	if (group_info == NULL) {
@@ -507,16 +518,16 @@ static int _config_current_group_push(const char *group_name)
 	INIT_LIST_HEAD(&group_info->list);
 	list_add_tail(&group_info->list, &dns_conf_group_info_list);
 
-	domain_rule = _config_domain_rule_group_get(group_name);
-	if (domain_rule == NULL) {
-		domain_rule = _config_domain_rule_group_new(group_name);
-		if (domain_rule == NULL) {
+	group_rule = _config_rule_group_get(group_name);
+	if (group_rule == NULL) {
+		group_rule = _config_rule_group_new(group_name);
+		if (group_rule == NULL) {
 			goto errout;
 		}
 	}
 
 	group_info->group_name = group_name;
-	group_info->domain_rule = domain_rule;
+	group_info->rule = group_rule;
 
 	dns_conf_current_group_info = group_info;
 	if (dns_conf_default_group_info == NULL) {
@@ -1003,79 +1014,86 @@ static int _config_domain_iter_free(void *data, const unsigned char *key, uint32
 	return _config_domain_rule_free(domain_rule);
 }
 
-static struct dns_conf_doamin_rule_group *_config_domain_rule_group_get(const char *group_name)
+static struct dns_conf_group *_config_rule_group_get(const char *group_name)
 {
 	uint32_t key = 0;
-	struct dns_conf_doamin_rule_group *domain_rule_group = NULL;
+	struct dns_conf_group *rule_group = NULL;
 	if (group_name == NULL) {
 		group_name = "";
 	}
 
 	key = hash_string(group_name);
-	hash_for_each_possible(dns_conf_domain_rule.group, domain_rule_group, node, key)
+	hash_for_each_possible(dns_conf_rule.group, rule_group, node, key)
 	{
-		if (strncmp(domain_rule_group->group_name, group_name, DNS_GROUP_NAME_LEN) == 0) {
-			return domain_rule_group;
+		if (strncmp(rule_group->group_name, group_name, DNS_GROUP_NAME_LEN) == 0) {
+			return rule_group;
 		}
 	}
 
 	return NULL;
 }
 
-struct dns_conf_doamin_rule_group *dns_server_get_domain_rule_group(const char *group_name, int no_fallback_default)
+struct dns_conf_group *dns_server_get_rule_group(const char *group_name, int no_fallback_default)
 {
-	struct dns_conf_doamin_rule_group *domain_rule_group = _config_domain_rule_group_get(group_name);
-	if (domain_rule_group) {
-		return domain_rule_group;
+	struct dns_conf_group *rule_group = _config_rule_group_get(group_name);
+	if (rule_group) {
+		return rule_group;
 	}
 
 	if (no_fallback_default) {
 		return NULL;
 	}
 
-	return dns_conf_domain_rule.default_rule;
+	return dns_conf_rule.default_conf;
 }
 
-static struct dns_conf_doamin_rule_group *_config_domain_rule_group_new(const char *group_name)
+static struct dns_conf_group *_config_rule_group_new(const char *group_name)
 {
-	struct dns_conf_doamin_rule_group *domain_rule_group = NULL;
+	struct dns_conf_group *rule_group = NULL;
 	uint32_t key = 0;
 
-	domain_rule_group = malloc(sizeof(*domain_rule_group));
-	if (domain_rule_group == NULL) {
+	rule_group = malloc(sizeof(*rule_group));
+	if (rule_group == NULL) {
 		return NULL;
 	}
 
-	memset(domain_rule_group, 0, sizeof(*domain_rule_group));
-	domain_rule_group->group_name = group_name;
-	INIT_HLIST_NODE(&domain_rule_group->node);
-	art_tree_init(&domain_rule_group->tree);
+	memset(rule_group, 0, sizeof(*rule_group));
+	rule_group->group_name = group_name;
+
+	INIT_HLIST_NODE(&rule_group->node);
+	art_tree_init(&rule_group->domain_rule.tree);
+
+	rule_group->address_rule.ipv4 = New_Radix();
+	rule_group->address_rule.ipv6 = New_Radix();
+
 	key = hash_string(group_name);
-	hash_add(dns_conf_domain_rule.group, &domain_rule_group->node, key);
+	hash_add(dns_conf_rule.group, &rule_group->node, key);
 
-	return domain_rule_group;
+	return rule_group;
 }
 
-static void _config_domain_rule_remove(struct dns_conf_doamin_rule_group *domain_rule_group)
+static void _config_rule_group_remove(struct dns_conf_group *rule_group)
 {
-	hlist_del_init(&domain_rule_group->node);
-	art_iter(&domain_rule_group->tree, _config_domain_iter_free, NULL);
-	art_tree_destroy(&domain_rule_group->tree);
-	free(domain_rule_group);
+	hlist_del_init(&rule_group->node);
+	art_iter(&rule_group->domain_rule.tree, _config_domain_iter_free, NULL);
+	art_tree_destroy(&rule_group->domain_rule.tree);
+	Destroy_Radix(rule_group->address_rule.ipv4, _config_ip_iter_free, NULL);
+	Destroy_Radix(rule_group->address_rule.ipv6, _config_ip_iter_free, NULL);
+	free(rule_group);
 }
 
-static void _config_domain_destroy(void)
+static void _config_rule_group_destroy(void)
 {
-	struct dns_conf_doamin_rule_group *group;
+	struct dns_conf_group *group;
 	struct hlist_node *tmp = NULL;
 	unsigned long i = 0;
 
-	hash_for_each_safe(dns_conf_domain_rule.group, i, tmp, group, node)
+	hash_for_each_safe(dns_conf_rule.group, i, tmp, group, node)
 	{
-		_config_domain_rule_remove(group);
+		_config_rule_group_remove(group);
 	}
 
-	dns_conf_domain_rule.default_rule = NULL;
+	dns_conf_rule.default_conf = NULL;
 }
 
 static int _config_set_rule_each_from_list(const char *file, set_rule_add_func callback, void *priv)
@@ -1226,7 +1244,7 @@ static __attribute__((unused)) struct dns_domain_rule *_config_domain_rule_get(c
 		return NULL;
 	}
 
-	return art_search(&_config_current_group()->domain_rule->tree, (unsigned char *)domain_key, len);
+	return art_search(&_config_current_rule_group()->domain_rule.tree, (unsigned char *)domain_key, len);
 }
 
 static int _config_domain_rule_add(const char *domain, enum domain_rule type, void *rule)
@@ -1258,7 +1276,7 @@ static int _config_domain_rule_add(const char *domain, enum domain_rule type, vo
 	}
 
 	/* Get existing or create domain rule */
-	domain_rule = art_search(&_config_current_group()->domain_rule->tree, (unsigned char *)domain_key, len);
+	domain_rule = art_search(&_config_current_rule_group()->domain_rule.tree, (unsigned char *)domain_key, len);
 	if (domain_rule == NULL) {
 		add_domain_rule = malloc(sizeof(*add_domain_rule));
 		if (add_domain_rule == NULL) {
@@ -1281,8 +1299,8 @@ static int _config_domain_rule_add(const char *domain, enum domain_rule type, vo
 
 	/* update domain rule */
 	if (add_domain_rule) {
-		old_domain_rule =
-			art_insert(&_config_current_group()->domain_rule->tree, (unsigned char *)domain_key, len, add_domain_rule);
+		old_domain_rule = art_insert(&_config_current_rule_group()->domain_rule.tree, (unsigned char *)domain_key, len,
+									 add_domain_rule);
 		if (old_domain_rule) {
 			_config_domain_rule_free(old_domain_rule);
 		}
@@ -1320,7 +1338,7 @@ static int _config_domain_rule_delete(const char *domain)
 	}
 
 	/* delete existing rules */
-	void *rule = art_delete(&_config_current_group()->domain_rule->tree, (unsigned char *)domain_key, len);
+	void *rule = art_delete(&_config_current_rule_group()->domain_rule.tree, (unsigned char *)domain_key, len);
 	if (rule) {
 		_config_domain_rule_free(rule);
 	}
@@ -1363,7 +1381,7 @@ static int _config_domain_rule_flag_set(const char *domain, unsigned int flag, u
 	}
 
 	/* Get existing or create domain rule */
-	domain_rule = art_search(&_config_current_group()->domain_rule->tree, (unsigned char *)domain_key, len);
+	domain_rule = art_search(&_config_current_rule_group()->domain_rule.tree, (unsigned char *)domain_key, len);
 	if (domain_rule == NULL) {
 		add_domain_rule = malloc(sizeof(*add_domain_rule));
 		if (add_domain_rule == NULL) {
@@ -1393,8 +1411,8 @@ static int _config_domain_rule_flag_set(const char *domain, unsigned int flag, u
 
 	/* update domain rule */
 	if (add_domain_rule) {
-		old_domain_rule =
-			art_insert(&_config_current_group()->domain_rule->tree, (unsigned char *)domain_key, len, add_domain_rule);
+		old_domain_rule = art_insert(&_config_current_rule_group()->domain_rule.tree, (unsigned char *)domain_key, len,
+									 add_domain_rule);
 		if (old_domain_rule) {
 			_config_domain_rule_free(old_domain_rule);
 		}
@@ -2976,10 +2994,10 @@ static radix_node_t *_create_addr_node(const char *addr)
 
 	switch (prefix.family) {
 	case AF_INET:
-		tree = dns_conf_address_rule.ipv4;
+		tree = _config_current_rule_group()->address_rule.ipv4;
 		break;
 	case AF_INET6:
-		tree = dns_conf_address_rule.ipv6;
+		tree = _config_current_rule_group()->address_rule.ipv6;
 		break;
 	}
 
@@ -5055,11 +5073,9 @@ static int _config_client_rules(void *data, int argc, char *argv[])
 		}
 	}
 
-	if (server_flag != 0) {
-		if (_config_client_rule_flag_set(client, server_flag, 0) != 0) {
-			tlog(TLOG_ERROR, "set client rule flags failed.");
-			goto errout;
-		}
+	if (_config_client_rule_flag_set(client, server_flag, 0) != 0) {
+		tlog(TLOG_ERROR, "set client rule flags failed.");
+		goto errout;
 	}
 
 	return 0;
@@ -5240,6 +5256,7 @@ static struct config_item _config_item[] = {
 	CONF_INT("audit-num", &dns_conf_audit_num, 0, 1024),
 	CONF_YESNO("audit-console", &dns_conf_audit_console),
 	CONF_YESNO("audit-syslog", &dns_conf_audit_syslog),
+	CONF_YESNO("acl-enable", &dns_conf_acl_enable),
 	CONF_INT("rr-ttl", &dns_conf_rr_ttl, 0, CONF_INT_MAX),
 	CONF_INT("rr-ttl-min", &dns_conf_rr_ttl_min, 0, CONF_INT_MAX),
 	CONF_INT("rr-ttl-max", &dns_conf_rr_ttl_max, 0, CONF_INT_MAX),
@@ -5434,17 +5451,15 @@ const char *dns_conf_get_cache_dir(void)
 
 static int _dns_server_load_conf_init(void)
 {
-	dns_conf_address_rule.ipv4 = New_Radix();
-	dns_conf_address_rule.ipv6 = New_Radix();
 	dns_conf_client_rule.rule = New_Radix();
-	if (dns_conf_address_rule.ipv4 == NULL || dns_conf_address_rule.ipv6 == NULL || dns_conf_client_rule.rule == NULL) {
-		tlog(TLOG_WARN, "init radix tree failed.");
+	if (dns_conf_client_rule.rule == NULL) {
+		tlog(TLOG_WARN, "init client rule radix tree failed.");
 		return -1;
 	}
 
-	hash_init(dns_conf_domain_rule.group);
-	dns_conf_domain_rule.default_rule = _config_domain_rule_group_new("");
-	if (dns_conf_domain_rule.default_rule == NULL) {
+	hash_init(dns_conf_rule.group);
+	dns_conf_rule.default_conf = _config_rule_group_new("");
+	if (dns_conf_rule.default_conf == NULL) {
 		tlog(TLOG_WARN, "init default domain rule failed.");
 		return -1;
 	}
@@ -5498,17 +5513,15 @@ static void dns_server_bind_destroy(void)
 	dns_conf_bind_ip_num = 0;
 }
 
-static void _config_ip_rules_destroy(void)
+static void _config_client_rule_destroy(void)
 {
-	Destroy_Radix(dns_conf_address_rule.ipv4, _config_ip_iter_free, NULL);
-	Destroy_Radix(dns_conf_address_rule.ipv6, _config_ip_iter_free, NULL);
 	Destroy_Radix(dns_conf_client_rule.rule, _config_client_rule_iter_free_cb, NULL);
 }
 
 void dns_server_load_exit(void)
 {
-	_config_domain_destroy();
-	_config_ip_rules_destroy();
+	_config_rule_group_destroy();
+	_config_client_rule_destroy();
 	_config_ipset_table_destroy();
 	_config_nftset_table_destroy();
 	_config_group_table_destroy();

+ 18 - 13
src/dns_conf.h

@@ -280,17 +280,6 @@ struct dns_response_mode_rule {
 	enum response_mode_type mode;
 };
 
-struct dns_conf_doamin_rule_group {
-	struct hlist_node node;
-	art_tree tree;
-	const char *group_name;
-};
-
-struct dns_conf_domain_rule {
-	struct dns_conf_doamin_rule_group *default_rule;
-	DECLARE_HASHTABLE(group, 8);
-};
-
 struct dns_group_table {
 	DECLARE_HASHTABLE(group, 8);
 };
@@ -411,6 +400,22 @@ struct dns_conf_address_rule {
 	radix_tree_t *ipv6;
 };
 
+struct dns_conf_domain_rule {
+	art_tree tree;
+};
+
+struct dns_conf_group {
+	struct hlist_node node;
+	struct dns_conf_domain_rule domain_rule;
+	struct dns_conf_address_rule address_rule;
+	const char *group_name;
+};
+
+struct dns_conf_rule {
+	struct dns_conf_group *default_conf;
+	DECLARE_HASHTABLE(group, 8);
+};
+
 struct dns_client_rule {
 	atomic_t refcnt;
 	enum client_rule rule;
@@ -615,7 +620,6 @@ extern int dns_conf_audit_syslog;
 
 extern char dns_conf_server_name[DNS_MAX_SERVER_NAME_LEN];
 extern struct dns_conf_domain_rule dns_conf_domain_rule;
-extern struct dns_conf_address_rule dns_conf_address_rule;
 extern struct dns_conf_client_rule dns_conf_client_rule;
 
 extern int dns_conf_dualstack_ip_selection;
@@ -636,6 +640,7 @@ extern int dns_conf_nftset_timeout_enable;
 extern int dns_conf_nftset_debug_enable;
 extern int dns_conf_local_ttl;
 extern int dns_conf_mdns_lookup;
+extern int dns_conf_acl_enable;
 
 extern int dns_conf_force_no_cname;
 
@@ -663,7 +668,7 @@ struct dns_proxy_names *dns_server_get_proxy_nams(const char *proxyname);
 
 struct dns_srv_records *dns_server_get_srv_record(const char *domain);
 
-struct dns_conf_doamin_rule_group *dns_server_get_domain_rule_group(const char *group_name, int no_fallback_default);
+struct dns_conf_group *dns_server_get_rule_group(const char *group_name, int no_fallback_default);
 
 extern int config_additional_file(void *data, int argc, char *argv[]);
 

+ 45 - 17
src/dns_server.c

@@ -228,6 +228,7 @@ struct dns_request {
 	atomic_t refcnt;
 
 	struct dns_server_conn_head *conn;
+	struct dns_conf_group *conf;
 	uint32_t server_flags;
 	char dns_group_name[DNS_GROUP_NAME_LEN];
 
@@ -3076,6 +3077,10 @@ static struct dns_ip_rules *_dns_server_ip_rule_get(struct dns_request *request,
 	radix_node_t *node = NULL;
 	struct dns_ip_rules *rule = NULL;
 
+	if (request->conf == NULL) {
+		return NULL;
+	}
+
 	/* Match IP address rules */
 	if (prefix_from_blob(addr, addr_len, addr_len * 8, &prefix) == NULL) {
 		return NULL;
@@ -3083,10 +3088,10 @@ static struct dns_ip_rules *_dns_server_ip_rule_get(struct dns_request *request,
 
 	switch (prefix.family) {
 	case AF_INET:
-		node = radix_search_best(dns_conf_address_rule.ipv4, &prefix);
+		node = radix_search_best(request->conf->address_rule.ipv4, &prefix);
 		break;
 	case AF_INET6:
-		node = radix_search_best(dns_conf_address_rule.ipv6, &prefix);
+		node = radix_search_best(request->conf->address_rule.ipv6, &prefix);
 		break;
 	default:
 		break;
@@ -4631,13 +4636,15 @@ static void _dns_server_get_domain_rule_by_domain(struct dns_request *request, c
 	unsigned char matched_key[DNS_MAX_CNAME_LEN];
 	struct rule_walk_args walk_args;
 	int i = 0;
-	struct dns_conf_doamin_rule_group *domain_rule_group = NULL;
-	int no_fallback_default_rule = 0;
 
 	if (request->skip_domain_rule != 0) {
 		return;
 	}
 
+	if (request->conf == NULL) {
+		return;
+	}
+
 	memset(&walk_args, 0, sizeof(walk_args));
 	walk_args.args = request;
 
@@ -4652,17 +4659,8 @@ static void _dns_server_get_domain_rule_by_domain(struct dns_request *request, c
 	domain_len++;
 	domain_key[domain_len] = 0;
 
-	if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULES) == 0) {
-		no_fallback_default_rule = 1;
-	}
-
-	domain_rule_group = dns_server_get_domain_rule_group(request->dns_group_name, no_fallback_default_rule);
-	if (domain_rule_group == NULL) {
-		return;
-	}
-
 	/* find domain rule */
-	art_substring_walk(&domain_rule_group->tree, (unsigned char *)domain_key, domain_len, _dns_server_get_rules,
+	art_substring_walk(&request->conf->domain_rule.tree, (unsigned char *)domain_key, domain_len, _dns_server_get_rules,
 					   &walk_args);
 	if (likely(dns_conf_log_level > TLOG_DEBUG)) {
 		return;
@@ -4945,6 +4943,7 @@ static struct dns_request *_dns_server_new_child_request(struct dns_request *req
 	child_request->parent_request = request;
 	child_request->qtype = qtype;
 	child_request->qclass = request->qclass;
+	child_request->conf = request->conf;
 
 	if (request->has_ecs) {
 		memcpy(&child_request->ecs, &request->ecs, sizeof(child_request->ecs));
@@ -5599,15 +5598,16 @@ static void _dns_server_request_set_client(struct dns_request *request, struct d
 static int _dns_server_request_set_client_rules(struct dns_request *request, struct dns_client_rules *client_rule)
 {
 	if (client_rule == NULL) {
-		if (_dns_server_has_bind_flag(request, BIND_FLAG_ACL) == 0) {
+		if (_dns_server_has_bind_flag(request, BIND_FLAG_ACL) == 0 || dns_conf_acl_enable) {
 			request->send_tick = get_tick_count();
 			request->rcode = DNS_RC_REFUSED;
+			request->no_cache = 1;
 			return -1;
 		}
 		return 0;
 	}
 
-	tlog(TLOG_DEBUG, "match client rule.\n");
+	tlog(TLOG_DEBUG, "match client rule.");
 
 	if (client_rule->rules[CLIENT_RULE_GROUP]) {
 		struct client_rule_group *group = (struct client_rule_group *)client_rule->rules[CLIENT_RULE_GROUP];
@@ -5924,6 +5924,7 @@ static int _dns_server_query_dualstack(struct dns_request *request)
 	request_dualstack->has_cname_loop = request->has_cname_loop;
 	request_dualstack->prefetch = request->prefetch;
 	request_dualstack->prefetch_flags = request->prefetch_flags;
+	request_dualstack->conf = request->conf;
 	_dns_server_request_get(request);
 	request_dualstack->dualstack_request = request;
 	_dns_server_request_set_callback(request_dualstack, dns_server_dualstack_callback, request);
@@ -5948,6 +5949,25 @@ errout:
 	return ret;
 }
 
+static int _dns_server_setup_request_conf(struct dns_request *request)
+{
+	int no_fallback_default_rule = 0;
+	struct dns_conf_group *rule_group = NULL;
+
+	if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULES) == 0) {
+		no_fallback_default_rule = 1;
+	}
+
+	rule_group = dns_server_get_rule_group(request->dns_group_name, no_fallback_default_rule);
+	if (rule_group == NULL) {
+		return -1;
+	}
+
+	request->conf = rule_group;
+
+	return 0;
+}
+
 static int _dns_server_do_query(struct dns_request *request, int skip_notify_event)
 {
 	int ret = -1;
@@ -5963,6 +5983,10 @@ static int _dns_server_do_query(struct dns_request *request, int skip_notify_eve
 
 	request->send_tick = get_tick_count();
 
+	if (_dns_server_setup_request_conf(request) != 0) {
+		goto errout;
+	}
+
 	/* lookup domain rule */
 	_dns_server_get_domain_rule(request);
 
@@ -5975,6 +5999,10 @@ static int _dns_server_do_query(struct dns_request *request, int skip_notify_eve
 		safe_strncpy(request->dns_group_name, group_name, DNS_GROUP_NAME_LEN);
 	}
 
+	if (_dns_server_setup_request_conf(request) != 0) {
+		goto errout;
+	}
+
 	if (_dns_server_mdns_query_setup(request, group_name, &request_domain, domain_buffer, sizeof(domain_buffer)) != 0) {
 		goto errout;
 	}
@@ -6230,11 +6258,11 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
 		}
 		request->send_tick = get_tick_count();
 		request->rcode = DNS_RC_REFUSED;
+		request->no_cache = 1;
 		ret = 0;
 		goto errout;
 	}
 
-
 	ret = _dns_server_request_set_client_rules(request, client_rules);
 	if (ret != 0) {
 		ret = 0;

+ 44 - 0
test/cases/test-client-rule.cc

@@ -100,3 +100,47 @@ group-end
 	EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.com");
 	EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
 }
+
+TEST_F(ClientRule, acl)
+{
+	smartdns::MockServer server_upstream;
+	smartdns::Server server;
+
+	server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
+		if (request->qtype != DNS_T_A) {
+			return smartdns::SERVER_REQUEST_SOA;
+		}
+
+		smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
+		return smartdns::SERVER_REQUEST_OK;
+	});
+
+	/* this ip will be discard, but is reachable */
+	server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
+
+	auto ipaddr = smartdns::GetAvailableIPAddresses();
+	if (ipaddr.size() < 0) {
+		return;
+	}
+
+	std::string confstr = R"""(bind [::]:60053
+server 127.0.0.1:61053
+acl-enable yes
+)""";
+
+	confstr += "client-rules " + ipaddr[0] + "\n";
+
+	server.Start(confstr);
+	smartdns::Client client;
+	ASSERT_TRUE(client.Query("b.com", 60053));
+	std::cout << client.GetResult() << std::endl;
+	EXPECT_EQ(client.GetStatus(), "REFUSED");
+	ASSERT_EQ(client.GetAnswerNum(), 0);
+
+	ASSERT_TRUE(client.Query("b.com", 60053, ipaddr[0]));
+	std::cout << client.GetResult() << std::endl;
+	ASSERT_EQ(client.GetAnswerNum(), 1);
+	EXPECT_EQ(client.GetStatus(), "NOERROR");
+	EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.com");
+	EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
+}

+ 70 - 2
test/cases/test-group.cc

@@ -48,6 +48,9 @@ server udp://127.0.0.1:61053 -e
 client-rules 127.0.0.1
 address /a.com/1.1.1.1
 domain-rules /b.com/ -address 4.5.6.7
+# should pop all groups
+group-begin dummy
+address /a.com/9.9.9.9
 )""";
 	ofs.flush();
 
@@ -87,11 +90,76 @@ server udp://127.0.0.1:61053
 
 	auto ipaddr = smartdns::GetAvailableIPAddresses();
 	if (ipaddr.size() > 0) {
-		ASSERT_TRUE(client.Query("b.com", 60053, ipaddr[0]));
+		ASSERT_TRUE(client.Query("a.com", 60053, ipaddr[0]));
 		std::cout << client.GetResult() << std::endl;
 		ASSERT_EQ(client.GetAnswerNum(), 1);
 		EXPECT_EQ(client.GetStatus(), "NOERROR");
-		EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.com");
+		EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
 		EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
 	}
 }
+
+TEST_F(Group, conf_file_ip_rule)
+{
+	smartdns::MockServer server_upstream;
+	smartdns::MockServer server_upstream2;
+	smartdns::Server server;
+	std::string file = "/tmp/smartdns_conf_file" + smartdns::GenerateRandomString(5) + ".conf";
+	std::ofstream ofs(file);
+	ASSERT_TRUE(ofs.is_open());
+	Defer
+	{
+		ofs.close();
+		unlink(file.c_str());
+	};
+
+	ofs << R"""(
+server udp://127.0.0.1:61053 -e
+client-rules 127.0.0.1
+ignore-ip 7.8.9.10
+group-begin dummy
+ignore-ip 1.2.3.4
+ignore-ip 7.8.9.10
+)""";
+	ofs.flush();
+
+	server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
+		if (request->qtype != DNS_T_A) {
+			return smartdns::SERVER_REQUEST_SOA;
+		}
+
+		smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
+		smartdns::MockServer::AddIP(request, request->domain.c_str(), "7.8.9.10", 611);
+		return smartdns::SERVER_REQUEST_OK;
+	});
+
+	server_upstream2.Start("udp://0.0.0.0:62053",
+						   [](struct smartdns::ServerRequestContext *request) { return smartdns::SERVER_REQUEST_SOA; });
+
+	/* this ip will be discard, but is reachable */
+	server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 20);
+	server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 10);
+
+	server.Start(R"""(bind [::]:60053
+conf-file /tmp/smartdns_conf_file*.conf -g client
+server udp://127.0.0.1:61053
+ignore-ip 1.2.3.4
+)""");
+	smartdns::Client client;
+	ASSERT_TRUE(client.Query("a.com", 60053));
+	std::cout << client.GetResult() << std::endl;
+	ASSERT_EQ(client.GetAnswerNum(), 1);
+	EXPECT_EQ(client.GetStatus(), "NOERROR");
+	EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
+	EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
+
+	auto ipaddr = smartdns::GetAvailableIPAddresses();
+	if (ipaddr.size() > 0) {
+		ASSERT_TRUE(client.Query("a.com", 60053, ipaddr[0]));
+		std::cout << client.GetResult() << std::endl;
+		ASSERT_EQ(client.GetAnswerNum(), 1);
+		EXPECT_EQ(client.GetStatus(), "NOERROR");
+		EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
+		EXPECT_EQ(client.GetAnswer()[0].GetData(), "7.8.9.10");
+	}
+}