Browse Source

feature: support ipset, nftset for bind option

Nick Peng 2 years ago
parent
commit
c9f7dad42f

+ 2 - 0
etc/smartdns/smartdns.conf

@@ -40,6 +40,8 @@
 #   -no-rule-soa: Skip address SOA(#) rules.
 #   -no-rule-soa: Skip address SOA(#) rules.
 #   -no-dualstack-selection: Disable dualstack ip selection.
 #   -no-dualstack-selection: Disable dualstack ip selection.
 #   -force-aaaa-soa: force AAAA query return SOA.
 #   -force-aaaa-soa: force AAAA query return SOA.
+#   -ipset ipsetname: use ipset rule.
+#   -nftset nftsetname: use nftset rule.
 # example: 
 # example: 
 #  IPV4: 
 #  IPV4: 
 #    bind :53
 #    bind :53

+ 21 - 0
package/luci-compat/files/luci/model/cbi/smartdns/smartdns.lua

@@ -358,6 +358,27 @@ o.cfgvalue    = function(...)
     return Flag.cfgvalue(...) or "0"
     return Flag.cfgvalue(...) or "0"
 end
 end
 
 
+o = s:taboption("seconddns", Value, "seconddns_ipset_name", translate("IPset Name"), translate("IPset name."))
+o.rmempty = true
+o.datatype = "hostname"
+o.rempty = true
+
+o = s:taboption("seconddns", Value, "seconddns_nftset_name", translate("NFTset Name"), translate("NFTset name, format: [#[4|6]:[family#table#set]]"))
+o.rmempty = true
+o.datatype = "string"
+o.rempty = true
+function o.validate(self, value) 
+    if (value == "") then
+        return value
+    end
+
+    if (value:match("#[4|6]:[a-zA-Z0-9%-_]+#[a-zA-Z0-9%-_]+#[a-zA-Z0-9%-_]+$")) then
+        return value
+    end
+
+    return nil, translate("NFTset name format error, format: [#[4|6]:[family#table#set]]")
+end
+
 ----- Proxy server settings
 ----- Proxy server settings
 o = s:taboption("proxy", Value, "proxy_server", translate("Proxy Server"), translate("Proxy Server URL, format: [socks5|http]://user:pass@ip:port."));
 o = s:taboption("proxy", Value, "proxy_server", translate("Proxy Server"), translate("Proxy Server URL, format: [socks5|http]://user:pass@ip:port."));
 o.datatype = 'string';
 o.datatype = 'string';

+ 38 - 0
package/luci/files/root/www/luci-static/resources/view/smartdns/smartdns.js

@@ -431,6 +431,44 @@ return view.extend({
 		o.rmempty = false;
 		o.rmempty = false;
 		o.default = o.disabled;
 		o.default = o.disabled;
 
 
+		o = s.taboption("seconddns", form.Value, "seconddns_ipset_name", _("IPset Name"), _("IPset name."));
+		o.rmempty = true;
+		o.datatype = "string";
+		o.rempty = true;
+		o.validate = function (section_id, value) {
+			if (value == "") {
+				return true;
+			}
+
+			var ipset = value.split(",")
+			for (var i = 0; i < ipset.length; i++) {
+				if (!ipset[i].match(/^(#[4|6]:)?[a-zA-Z0-9\-_]+$/)) {
+					return _("ipset name format error, format: [#[4|6]:]ipsetname");
+				}
+			}
+
+			return true;
+		}
+
+		o = s.taboption("seconddns", form.Value, "seconddns_nftset_name", _("NFTset Name"), _("NFTset name, format: [#[4|6]:[family#table#set]]"));
+		o.rmempty = true;
+		o.datatype = "string";
+		o.rempty = true;
+		o.validate = function (section_id, value) {
+			if (value == "") {
+				return true;
+			}
+
+			var nftset = value.split(",")
+			for (var i = 0; i < nftset.length; i++) {
+				if (!nftset[i].match(/^#[4|6]:[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+$/)) {
+					return _("NFTset name format error, format: [#[4|6]:[family#table#set]]");
+				}
+			}
+
+			return true;
+		}
+
 		///////////////////////////////////////
 		///////////////////////////////////////
 		// DNS64 Settings
 		// DNS64 Settings
 		///////////////////////////////////////
 		///////////////////////////////////////

+ 10 - 2
package/openwrt/files/etc/init.d/smartdns

@@ -300,8 +300,10 @@ load_domain_rules()
 		conf_append "domain-rules" "/domain-set:${domain_set_name}-forwarding-file/ $domain_set_args"
 		conf_append "domain-rules" "/domain-set:${domain_set_name}-forwarding-file/ $domain_set_args"
 	}
 	}
 
 
-	conf_append "domain-set" "-name ${domain_set_name}-forwarding-list -file /etc/smartdns/domain-forwarding.list"
-	conf_append "domain-rules" "/domain-set:${domain_set_name}-forwarding-list/ $domain_set_args"
+	[ ! -z "$domain_set_args" ] && {
+		conf_append "domain-set" "-name ${domain_set_name}-forwarding-list -file /etc/smartdns/domain-forwarding.list"
+		conf_append "domain-rules" "/domain-set:${domain_set_name}-forwarding-list/ $domain_set_args"
+	}
 
 
 	config_get block_domain_set_file "$section" "block_domain_set_file"
 	config_get block_domain_set_file "$section" "block_domain_set_file"
 	[ ! -z "$block_domain_set_file" ] && {
 	[ ! -z "$block_domain_set_file" ] && {
@@ -430,6 +432,12 @@ load_second_server()
 	config_get_bool seconddns_force_aaaa_soa "$section" "seconddns_force_aaaa_soa" "0"
 	config_get_bool seconddns_force_aaaa_soa "$section" "seconddns_force_aaaa_soa" "0"
 	[ "$seconddns_force_aaaa_soa" = "1" ] && ARGS="$ARGS -force-aaaa-soa"
 	[ "$seconddns_force_aaaa_soa" = "1" ] && ARGS="$ARGS -force-aaaa-soa"
 
 
+	config_get seconddns_ipset_name "$section" "seconddns_ipset_name" ""
+	[ -z "$seconddns_ipset_name" ] || ARGS="$ARGS -ipset $seconddns_ipset_name"
+
+	config_get seconddns_nftset_name "$section" "seconddns_nftset_name" ""
+	[ -z "$seconddns_nftset_name" ] || ARGS="$ARGS -nftset $seconddns_nftset_name"
+
 	config_get_bool bind_device "$section" "bind_device" "0"
 	config_get_bool bind_device "$section" "bind_device" "0"
 	config_get bind_device_name "$section" "bind_device_name" "${lan_device}"
 	config_get bind_device_name "$section" "bind_device_name" "${lan_device}"
 	[ ! -z "$bind_device_name" ] && [ "$bind_device" = "1" ] && device="${bind_device_name}"
 	[ ! -z "$bind_device_name" ] && [ "$bind_device" = "1" ] && device="${bind_device_name}"

+ 178 - 1
src/dns_conf.c

@@ -1356,6 +1356,7 @@ static int _conf_domain_rule_nftset(char *domain, const char *nftsetname)
 			goto errout;
 			goto errout;
 		}
 		}
 		_dns_rule_put(&nftset_rule->head);
 		_dns_rule_put(&nftset_rule->head);
+		nftset_rule = NULL;
 	}
 	}
 
 
 	goto clear;
 	goto clear;
@@ -1802,6 +1803,143 @@ errout:
 	return -1;
 	return -1;
 }
 }
 
 
+static int _config_bind_ip_parser_nftset(struct dns_bind_ip *bind_ip, unsigned int *server_flag, const char *nftsetname)
+{
+	struct dns_nftset_rule *nftset_rule = NULL;
+	struct dns_nftset_rule **bind_nftset_rule = NULL;
+	const struct dns_nftset_name *nftset_name = NULL;
+	enum domain_rule type = DOMAIN_RULE_MAX;
+
+	char *setname = NULL;
+	char *tablename = NULL;
+	char *family = NULL;
+	char copied_name[DNS_MAX_NFTSET_NAMELEN + 1];
+
+	safe_strncpy(copied_name, nftsetname, DNS_MAX_NFTSET_NAMELEN);
+	for (char *tok = strtok(copied_name, ","); tok; tok = strtok(NULL, ",")) {
+		char *saveptr = NULL;
+		char *tok_set = NULL;
+
+		if (strncmp(tok, "#4:", 3U) == 0) {
+			bind_nftset_rule = &bind_ip->nftset_ipset_rule.nftset_ip;
+			type = DOMAIN_RULE_NFTSET_IP;
+		} else if (strncmp(tok, "#6:", 3U) == 0) {
+			bind_nftset_rule = &bind_ip->nftset_ipset_rule.nftset_ip6;
+			type = DOMAIN_RULE_NFTSET_IP6;
+		} else if (strncmp(tok, "-", 2U) == 0) {
+			continue;
+		} else {
+			return -1;
+		}
+
+		tok_set = tok + 3;
+
+		if (strncmp(tok_set, "-", 2U) == 0) {
+			*server_flag |= BIND_FLAG_NO_RULE_NFTSET;
+			continue;
+		}
+
+		family = strtok_r(tok_set, "#", &saveptr);
+		if (family == NULL) {
+			return -1;
+		}
+
+		tablename = strtok_r(NULL, "#", &saveptr);
+		if (tablename == NULL) {
+			return -1;
+		}
+
+		setname = strtok_r(NULL, "#", &saveptr);
+		if (setname == NULL) {
+			return -1;
+		}
+
+		/* new nftset domain */
+		nftset_name = _dns_conf_get_nftable(family, tablename, setname);
+		if (nftset_name == NULL) {
+			return -1;
+		}
+
+		nftset_rule = _new_dns_rule(type);
+		if (nftset_rule == NULL) {
+			return -1;
+		}
+
+		nftset_rule->nfttablename = nftset_name->nfttablename;
+		nftset_rule->nftsetname = nftset_name->nftsetname;
+		nftset_rule->familyname = nftset_name->nftfamilyname;
+		/* reference is 1 here */
+		*bind_nftset_rule = nftset_rule;
+
+		nftset_rule = NULL;
+	}
+
+	return 0;
+}
+
+static int _config_bind_ip_parser_ipset(struct dns_bind_ip *bind_ip, unsigned int *server_flag, const char *ipsetname)
+{
+	struct dns_ipset_rule **bind_ipset_rule = NULL;
+	struct dns_ipset_rule *ipset_rule = NULL;
+	const char *ipset = NULL;
+	enum domain_rule type = DOMAIN_RULE_MAX;
+
+	char copied_name[DNS_MAX_NFTSET_NAMELEN + 1];
+
+	safe_strncpy(copied_name, ipsetname, DNS_MAX_NFTSET_NAMELEN);
+
+	for (char *tok = strtok(copied_name, ","); tok; tok = strtok(NULL, ",")) {
+		if (tok[0] == '#') {
+			if (strncmp(tok, "#6:", 3U) == 0) {
+				bind_ipset_rule = &bind_ip->nftset_ipset_rule.ipset_ip6;
+				type = DOMAIN_RULE_IPSET_IPV6;
+			} else if (strncmp(tok, "#4:", 3U) == 0) {
+				bind_ipset_rule = &bind_ip->nftset_ipset_rule.ipset_ip;
+				type = DOMAIN_RULE_IPSET_IPV4;
+			} else {
+				goto errout;
+			}
+			tok += 3;
+		} else {
+			type = DOMAIN_RULE_IPSET;
+			bind_ipset_rule = &bind_ip->nftset_ipset_rule.ipset;
+		}
+
+		if (strncmp(tok, "-", 1) == 0) {
+			*server_flag |= BIND_FLAG_NO_RULE_IPSET;
+			continue;
+		}
+
+		if (bind_ipset_rule == NULL) {
+			continue;
+		}
+
+		/* new ipset domain */
+		ipset = _dns_conf_get_ipset(tok);
+		if (ipset == NULL) {
+			goto errout;
+		}
+
+		ipset_rule = _new_dns_rule(type);
+		if (ipset_rule == NULL) {
+			goto errout;
+		}
+
+		ipset_rule->ipsetname = ipset;
+		/* reference is 1 here */
+		*bind_ipset_rule = ipset_rule;
+		ipset_rule = NULL;
+	}
+
+	return 0;
+errout:
+	if (ipset_rule) {
+		_dns_rule_put(&ipset_rule->head);
+	}
+
+	return -1;
+}
+
 static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
 static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
 {
 {
 	int index = dns_conf_bind_ip_num;
 	int index = dns_conf_bind_ip_num;
@@ -1825,6 +1963,8 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
 		{"no-cache", no_argument, NULL, 'C'},  
 		{"no-cache", no_argument, NULL, 'C'},  
 		{"no-dualstack-selection", no_argument, NULL, 'D'},
 		{"no-dualstack-selection", no_argument, NULL, 'D'},
 		{"force-aaaa-soa", no_argument, NULL, 'F'},
 		{"force-aaaa-soa", no_argument, NULL, 'F'},
+		{"ipset", required_argument, NULL, 255},
+		{"nftset", required_argument, NULL, 256},
 		{NULL, no_argument, NULL, 0}
 		{NULL, no_argument, NULL, 0}
 	};
 	};
 	/* clang-format on */
 	/* clang-format on */
@@ -1908,6 +2048,14 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
 			server_flag |= BIND_FLAG_FORCE_AAAA_SOA;
 			server_flag |= BIND_FLAG_FORCE_AAAA_SOA;
 			break;
 			break;
 		}
 		}
+		case 255: {
+			_config_bind_ip_parser_ipset(bind_ip, &server_flag, optarg);
+			break;
+		}
+		case 256: {
+			_config_bind_ip_parser_nftset(bind_ip, &server_flag, optarg);
+			break;
+		}
 		default:
 		default:
 			break;
 			break;
 		}
 		}
@@ -3381,6 +3529,35 @@ static int _dns_server_load_conf_init(void)
 	return 0;
 	return 0;
 }
 }
 
 
+static void dns_server_bind_destroy(void)
+{
+	for (int i = 0; i < dns_conf_bind_ip_num; i++) {
+		struct dns_bind_ip *bind_ip = &dns_conf_bind_ip[i];
+
+		if (bind_ip->nftset_ipset_rule.ipset) {
+			_dns_rule_put(&bind_ip->nftset_ipset_rule.ipset->head);
+		}
+
+		if (bind_ip->nftset_ipset_rule.ipset_ip) {
+			_dns_rule_put(&bind_ip->nftset_ipset_rule.ipset_ip->head);
+		}
+
+		if (bind_ip->nftset_ipset_rule.ipset_ip6) {
+			_dns_rule_put(&bind_ip->nftset_ipset_rule.ipset_ip6->head);
+		}
+
+		if (bind_ip->nftset_ipset_rule.nftset_ip) {
+			_dns_rule_put(&bind_ip->nftset_ipset_rule.nftset_ip->head);
+		}
+
+		if (bind_ip->nftset_ipset_rule.nftset_ip6) {
+			_dns_rule_put(&bind_ip->nftset_ipset_rule.nftset_ip6->head);
+		}
+	}
+	memset(dns_conf_bind_ip, 0, sizeof(dns_conf_bind_ip));
+	dns_conf_bind_ip_num = 0;
+}
+
 void dns_server_load_exit(void)
 void dns_server_load_exit(void)
 {
 {
 	_config_domain_destroy();
 	_config_domain_destroy();
@@ -3395,7 +3572,7 @@ void dns_server_load_exit(void)
 	_config_proxy_table_destroy();
 	_config_proxy_table_destroy();
 
 
 	dns_conf_server_num = 0;
 	dns_conf_server_num = 0;
-	dns_conf_bind_ip_num = 0;
+	dns_server_bind_destroy();
 }
 }
 
 
 static int _config_add_default_server_if_needed(void)
 static int _config_add_default_server_if_needed(void)

+ 10 - 0
src/dns_conf.h

@@ -125,6 +125,7 @@ typedef enum {
 #define BIND_FLAG_NO_DUALSTACK_SELECTION (1 << 7)
 #define BIND_FLAG_NO_DUALSTACK_SELECTION (1 << 7)
 #define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
 #define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
 #define BIND_FLAG_NO_RULE_CNAME (1 << 9)
 #define BIND_FLAG_NO_RULE_CNAME (1 << 9)
+#define BIND_FLAG_NO_RULE_NFTSET (1 << 10)
 
 
 enum response_mode_type {
 enum response_mode_type {
 	DNS_RESPONSE_MODE_FIRST_PING_IP = 0,
 	DNS_RESPONSE_MODE_FIRST_PING_IP = 0,
@@ -359,6 +360,14 @@ struct dns_conf_address_rule {
 	radix_tree_t *ipv6;
 	radix_tree_t *ipv6;
 };
 };
 
 
+struct nftset_ipset_rules {
+	struct dns_ipset_rule *ipset;
+	struct dns_ipset_rule *ipset_ip;
+	struct dns_ipset_rule *ipset_ip6;
+	struct dns_nftset_rule *nftset_ip;
+	struct dns_nftset_rule *nftset_ip6;
+};
+
 struct dns_bind_ip {
 struct dns_bind_ip {
 	DNS_BIND_TYPE type;
 	DNS_BIND_TYPE type;
 	uint32_t flags;
 	uint32_t flags;
@@ -367,6 +376,7 @@ struct dns_bind_ip {
 	const char *ssl_cert_key_file;
 	const char *ssl_cert_key_file;
 	const char *ssl_cert_key_pass;
 	const char *ssl_cert_key_pass;
 	const char *group;
 	const char *group;
+	struct nftset_ipset_rules nftset_ipset_rule;
 };
 };
 
 
 struct dns_qtype_soa_list {
 struct dns_qtype_soa_list {

+ 54 - 0
src/dns_server.c

@@ -115,6 +115,7 @@ struct dns_server_conn_head {
 	atomic_t refcnt;
 	atomic_t refcnt;
 	const char *dns_group;
 	const char *dns_group;
 	uint32_t server_flags;
 	uint32_t server_flags;
+	struct nftset_ipset_rules *ipset_nftset_rule;
 };
 };
 
 
 struct dns_server_post_context {
 struct dns_server_post_context {
@@ -383,6 +384,34 @@ static int _dns_server_has_bind_flag(struct dns_request *request, uint32_t flag)
 	return -1;
 	return -1;
 }
 }
 
 
+static void *_dns_server_get_bind_ipset_nftset_rule(struct dns_request *request, enum domain_rule type)
+{
+	if (request->conn == NULL) {
+		return NULL;
+	}
+
+	if (request->conn->ipset_nftset_rule == NULL) {
+		return NULL;
+	}
+
+	switch (type) {
+	case DOMAIN_RULE_IPSET:
+		return request->conn->ipset_nftset_rule->ipset;
+	case DOMAIN_RULE_IPSET_IPV4:
+		return request->conn->ipset_nftset_rule->ipset_ip;
+	case DOMAIN_RULE_IPSET_IPV6:
+		return request->conn->ipset_nftset_rule->ipset_ip6;
+	case DOMAIN_RULE_NFTSET_IP:
+		return request->conn->ipset_nftset_rule->nftset_ip;
+	case DOMAIN_RULE_NFTSET_IP6:
+		return request->conn->ipset_nftset_rule->nftset_ip6;
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
 static int _dns_server_get_reply_ttl(struct dns_request *request, int ttl)
 static int _dns_server_get_reply_ttl(struct dns_request *request, int ttl)
 {
 {
 	int reply_ttl = ttl;
 	int reply_ttl = ttl;
@@ -1617,10 +1646,17 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 	rule_flags = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS);
 	rule_flags = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS);
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
 		ipset_rule = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET);
 		ipset_rule = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET);
+		if (ipset_rule == NULL) {
+			ipset_rule = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET);
+		}
 	}
 	}
 
 
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
 		ipset_rule_v4 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV4);
 		ipset_rule_v4 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV4);
+		if (ipset_rule_v4 == NULL) {
+			ipset_rule_v4 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET_IPV4);
+		}
+
 		if (ipset_rule == NULL && check_no_speed_rule && dns_conf_ipset_no_speed.ipv4_enable) {
 		if (ipset_rule == NULL && check_no_speed_rule && dns_conf_ipset_no_speed.ipv4_enable) {
 			ipset_rule_v4 = &dns_conf_ipset_no_speed.ipv4;
 			ipset_rule_v4 = &dns_conf_ipset_no_speed.ipv4;
 		}
 		}
@@ -1628,6 +1664,10 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 
 
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
 		ipset_rule_v6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV6);
 		ipset_rule_v6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV6);
+		if (ipset_rule_v6 == NULL) {
+			ipset_rule_v6 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET_IPV6);
+		}
+
 		if (ipset_rule_v6 == NULL && check_no_speed_rule && dns_conf_ipset_no_speed.ipv6_enable) {
 		if (ipset_rule_v6 == NULL && check_no_speed_rule && dns_conf_ipset_no_speed.ipv6_enable) {
 			ipset_rule_v6 = &dns_conf_ipset_no_speed.ipv6;
 			ipset_rule_v6 = &dns_conf_ipset_no_speed.ipv6;
 		}
 		}
@@ -1635,6 +1675,10 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 
 
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP_IGN) == 0) {
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP_IGN) == 0) {
 		nftset_ip = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP);
 		nftset_ip = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP);
+		if (nftset_ip == NULL) {
+			nftset_ip = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_NFTSET_IP);
+		}
+
 		if (nftset_ip == NULL && check_no_speed_rule && dns_conf_nftset_no_speed.ip_enable) {
 		if (nftset_ip == NULL && check_no_speed_rule && dns_conf_nftset_no_speed.ip_enable) {
 			nftset_ip = &dns_conf_nftset_no_speed.ip;
 			nftset_ip = &dns_conf_nftset_no_speed.ip;
 		}
 		}
@@ -1642,6 +1686,11 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 
 
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP6_IGN) == 0) {
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP6_IGN) == 0) {
 		nftset_ip6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP6);
 		nftset_ip6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP6);
+
+		if (nftset_ip6 == NULL) {
+			nftset_ip6 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_NFTSET_IP6);
+		}
+
 		if (nftset_ip6 == NULL && check_no_speed_rule && dns_conf_nftset_no_speed.ip6_enable) {
 		if (nftset_ip6 == NULL && check_no_speed_rule && dns_conf_nftset_no_speed.ip6_enable) {
 			nftset_ip6 = &dns_conf_nftset_no_speed.ip6;
 			nftset_ip6 = &dns_conf_nftset_no_speed.ip6;
 		}
 		}
@@ -5549,6 +5598,8 @@ static int _dns_server_tcp_accept(struct dns_server_conn_tcp_server *tcpserver,
 	tcpclient->head.type = DNS_CONN_TYPE_TCP_CLIENT;
 	tcpclient->head.type = DNS_CONN_TYPE_TCP_CLIENT;
 	tcpclient->head.server_flags = tcpserver->head.server_flags;
 	tcpclient->head.server_flags = tcpserver->head.server_flags;
 	tcpclient->head.dns_group = tcpserver->head.dns_group;
 	tcpclient->head.dns_group = tcpserver->head.dns_group;
+	tcpclient->head.ipset_nftset_rule = tcpserver->head.ipset_nftset_rule;
+
 	atomic_set(&tcpclient->head.refcnt, 0);
 	atomic_set(&tcpclient->head.refcnt, 0);
 	memcpy(&tcpclient->addr, &addr, addr_len);
 	memcpy(&tcpclient->addr, &addr, addr_len);
 	tcpclient->addr_len = addr_len;
 	tcpclient->addr_len = addr_len;
@@ -5985,6 +6036,8 @@ static int _dns_server_tls_accept(struct dns_server_conn_tls_server *tls_server,
 	tls_client->head.type = DNS_CONN_TYPE_TLS_CLIENT;
 	tls_client->head.type = DNS_CONN_TYPE_TLS_CLIENT;
 	tls_client->head.server_flags = tls_server->head.server_flags;
 	tls_client->head.server_flags = tls_server->head.server_flags;
 	tls_client->head.dns_group = tls_server->head.dns_group;
 	tls_client->head.dns_group = tls_server->head.dns_group;
+	tls_client->head.ipset_nftset_rule = tls_server->head.ipset_nftset_rule;
+
 	atomic_set(&tls_client->head.refcnt, 0);
 	atomic_set(&tls_client->head.refcnt, 0);
 	memcpy(&tls_client->addr, &addr, addr_len);
 	memcpy(&tls_client->addr, &addr, addr_len);
 	tls_client->addr_len = addr_len;
 	tls_client->addr_len = addr_len;
@@ -6688,6 +6741,7 @@ static int _dns_server_set_flags(struct dns_server_conn_head *head, struct dns_b
 	time(&head->last_request_time);
 	time(&head->last_request_time);
 	head->server_flags = bind_ip->flags;
 	head->server_flags = bind_ip->flags;
 	head->dns_group = bind_ip->group;
 	head->dns_group = bind_ip->group;
+	head->ipset_nftset_rule = &bind_ip->nftset_ipset_rule;
 	atomic_set(&head->refcnt, 0);
 	atomic_set(&head->refcnt, 0);
 	list_add(&head->list, &server.conn_list);
 	list_add(&head->list, &server.conn_list);