浏览代码

ipset: support global ipset and global nftset

Nick Peng 1 年之前
父节点
当前提交
94460d1171

+ 7 - 3
etc/smartdns/smartdns.conf

@@ -44,6 +44,8 @@
 #   -no-dualstack-selection: Disable dualstack ip selection.
 #   -no-dualstack-selection: Disable dualstack ip selection.
 #   -no-ip-alias: ignore ip alias.
 #   -no-ip-alias: ignore ip alias.
 #   -force-aaaa-soa: force AAAA query return SOA.
 #   -force-aaaa-soa: force AAAA query return SOA.
+#   -force-https-soa: force HTTPS query return SOA.
+#   -no-serve-expired: no serve expired.
 #   -ipset ipsetname: use ipset rule.
 #   -ipset ipsetname: use ipset rule.
 #   -nftset nftsetname: use nftset rule.
 #   -nftset nftsetname: use nftset rule.
 # example: 
 # example: 
@@ -284,9 +286,10 @@ log-level info
 # ipset-timeout [yes]
 # ipset-timeout [yes]
 
 
 # specific ipset to domain
 # specific ipset to domain
-# ipset /domain/[ipset|-]
-# ipset /www.example.com/block, set ipset with ipset name of block 
-# ipset /www.example.com/-, ignore this domain
+# ipset /domain/[ipsetname|#4:v4setname|#6:v6setname|-|#4:-|#6:-]
+# ipset [ipsetname|#4:v4setname|#6:v6setname], set global ipset.
+# ipset /www.example.com/block, set ipset with ipset name of block. 
+# ipset /www.example.com/-, ignore this domain.
 
 
 # add to ipset when ping is unreachable
 # add to ipset when ping is unreachable
 # ipset-no-speed ipsetname
 # ipset-no-speed ipsetname
@@ -306,6 +309,7 @@ log-level info
 
 
 # specific nftset to domain
 # specific nftset to domain
 # nftset /domain/[#4:ip#table#set,#6:ipv6#table#setv6]
 # nftset /domain/[#4:ip#table#set,#6:ipv6#table#setv6]
+# nftset [#4:ip#table#set,#6:ipv6#table#setv6] set global nftset.
 # nftset /www.example.com/ip#table#set, equivalent to 'nft add element ip table set { ... }'
 # nftset /www.example.com/ip#table#set, equivalent to 'nft add element ip table set { ... }'
 # nftset /www.example.com/-, ignore this domain
 # nftset /www.example.com/-, ignore this domain
 # nftset /www.example.com/#6:-, ignore ipv6
 # nftset /www.example.com/#6:-, ignore ipv6

+ 13 - 2
package/linux/install

@@ -24,6 +24,7 @@ showhelp()
 	echo "Options:"
 	echo "Options:"
 	echo " -i               install smartdns."
 	echo " -i               install smartdns."
 	echo " -u               uninstall smartdns."
 	echo " -u               uninstall smartdns."
+	echo " -U               upgrade install smartdns."
 	echo " --prefix [dir]   prefix directory."
 	echo " --prefix [dir]   prefix directory."
 	echo " -h               show this message."
 	echo " -h               show this message."
 }
 }
@@ -223,7 +224,7 @@ main()
 {
 {
 	ACTION=""
 	ACTION=""
 
 
-	OPTS=`getopt -o iuh --long help,prefix: \
+	OPTS=`getopt -o iuhU --long help,prefix: \
 		-n  "" -- "$@"`
 		-n  "" -- "$@"`
 
 
 	if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
 	if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
@@ -246,6 +247,9 @@ main()
 		-u )
 		-u )
 			ACTION="UNINSTALL"
 			ACTION="UNINSTALL"
 			shift ;;
 			shift ;;
+		-U )
+			ACTION="UPGRADE"
+			shift ;;
 		-- ) shift; break ;;
 		-- ) shift; break ;;
 		* ) break ;;
 		* ) break ;;
   		esac
   		esac
@@ -262,7 +266,14 @@ main()
 	elif [ "$ACTION" = "UNINSTALL" ]; then
 	elif [ "$ACTION" = "UNINSTALL" ]; then
 		uninstall_smartdns
 		uninstall_smartdns
 		return 0
 		return 0
-	fi	
+	elif [ "$ACTION" = "UPGRADE" ]; then
+		uninstall_smartdns
+		install_smartdns
+		return $?
+	else
+		showhelp
+		return 1
+	fi
 
 
 }
 }
 
 

+ 29 - 1
package/luci-compat/files/luci/model/cbi/smartdns/smartdns.lua

@@ -271,6 +271,11 @@ o.cfgvalue    = function(...)
     return Flag.cfgvalue(...) or "1"
     return Flag.cfgvalue(...) or "1"
 end
 end
 
 
+o = s:taboption("advanced", Value, "ipset_name", translate("IPset Name"), translate("IPset name."))
+o.rmempty = true
+o.datatype = "string"
+o.rempty = true
+
 ---- Ipset no speed.
 ---- Ipset no speed.
 o = s:taboption("advanced", Value, "ipset_no_speed", translate("No Speed IPset Name"), 
 o = s:taboption("advanced", Value, "ipset_no_speed", translate("No Speed IPset Name"), 
     translate("Ipset name, Add domain result to ipset when speed check fails."));
     translate("Ipset name, Add domain result to ipset when speed check fails."));
@@ -278,6 +283,22 @@ o.rmempty = true;
 o.datatype = "hostname";
 o.datatype = "hostname";
 o.rempty = true;
 o.rempty = true;
 
 
+o = s:taboption("advanced", Value, "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
+
 ---- NFTset no speed.
 ---- NFTset no speed.
 o = s:taboption("advanced", Value, "nftset_no_speed", translate("No Speed NFTset Name"), 
 o = s:taboption("advanced", Value, "nftset_no_speed", translate("No Speed NFTset Name"), 
     translate("Nftset name, Add domain result to nftset when speed check fails, format: [#[4|6]:[family#table#set]]"));
     translate("Nftset name, Add domain result to nftset when speed check fails, format: [#[4|6]:[family#table#set]]"));
@@ -434,6 +455,13 @@ o.cfgvalue    = function(...)
     return Flag.cfgvalue(...) or "0"
     return Flag.cfgvalue(...) or "0"
 end
 end
 
 
+o = s:taboption("seconddns", Flag, "seconddns_force_https_soa", translate("Force HTTPS SOA"), translate("Force HTTPS SOA."))
+o.rmempty     = false
+o.default     = o.disabled
+o.cfgvalue    = function(...)
+    return Flag.cfgvalue(...) or "0"
+end
+
 o = s:taboption("seconddns", Flag, "seconddns_no_ip_alias", translate("Skip IP Alias"))
 o = s:taboption("seconddns", Flag, "seconddns_no_ip_alias", translate("Skip IP Alias"))
 o.rmempty     = true
 o.rmempty     = true
 o.default     = o.disabled
 o.default     = o.disabled
@@ -443,7 +471,7 @@ end
 
 
 o = s:taboption("seconddns", Value, "seconddns_ipset_name", translate("IPset Name"), translate("IPset name."))
 o = s:taboption("seconddns", Value, "seconddns_ipset_name", translate("IPset Name"), translate("IPset name."))
 o.rmempty = true
 o.rmempty = true
-o.datatype = "hostname"
+o.datatype = "string"
 o.rempty = true
 o.rempty = true
 
 
 o = s:taboption("seconddns", Value, "seconddns_nftset_name", translate("NFTset Name"), translate("NFTset name, format: [#[4|6]:[family#table#set]]"))
 o = s:taboption("seconddns", Value, "seconddns_nftset_name", translate("NFTset Name"), translate("NFTset name, format: [#[4|6]:[family#table#set]]"))

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

@@ -331,6 +331,26 @@ return view.extend({
 		o.rmempty = false;
 		o.rmempty = false;
 		o.default = o.enabled;
 		o.default = o.enabled;
 
 
+		// ipset name;
+		o = s.taboption("advanced", form.Value, "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;
+		}
+
 		// Ipset no speed.
 		// Ipset no speed.
 		o = s.taboption("advanced", form.Value, "ipset_no_speed", _("No Speed IPset Name"),
 		o = s.taboption("advanced", form.Value, "ipset_no_speed", _("No Speed IPset Name"),
 			_("Ipset name, Add domain result to ipset when speed check fails."));
 			_("Ipset name, Add domain result to ipset when speed check fails."));
@@ -351,6 +371,26 @@ return view.extend({
 
 
 			return true;
 			return true;
 		}
 		}
+		
+		// NFTset name;
+		o = s.taboption("advanced", form.Value, "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;
+		}
 
 
 		// NFTset no speed.
 		// NFTset no speed.
 		o = s.taboption("advanced", form.Value, "nftset_no_speed", _("No Speed NFTset Name"),
 		o = s.taboption("advanced", form.Value, "nftset_no_speed", _("No Speed NFTset Name"),
@@ -503,6 +543,11 @@ return view.extend({
 		o = s.taboption("seconddns", form.Flag, "seconddns_force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
 		o = s.taboption("seconddns", form.Flag, "seconddns_force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
 		o.rmempty = true;
 		o.rmempty = true;
 		o.default = o.disabled;
 		o.default = o.disabled;
+		
+		// Force HTTPS SOA
+		o = s.taboption("seconddns", form.Flag, "seconddns_force_https_soa", _("Force HTTPS SOA"), _("Force HTTPS SOA."));
+		o.rmempty = true;
+		o.default = o.disabled;
 
 
 		o = s.taboption("seconddns", form.Flag, "seconddns_no_ip_alias", _("Skip IP Alias"));
 		o = s.taboption("seconddns", form.Flag, "seconddns_no_ip_alias", _("Skip IP Alias"));
 		o.rmempty = true;
 		o.rmempty = true;

+ 9 - 0
package/openwrt/files/etc/init.d/smartdns

@@ -484,6 +484,9 @@ 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_bool seconddns_force_https_soa "$section" "seconddns_force_https_soa" "0"
+	[ "$seconddns_force_https_soa" = "1" ] && ARGS="$ARGS -force-https-soa"
+
 	config_get_bool seconddns_no_ip_alias "$section" "seconddns_no_ip_alias" "0"
 	config_get_bool seconddns_no_ip_alias "$section" "seconddns_no_ip_alias" "0"
 	[ "$seconddns_no_ip_alias" = "1" ] && ARGS="$ARGS -no-ip-alias"
 	[ "$seconddns_no_ip_alias" = "1" ] && ARGS="$ARGS -no-ip-alias"
 
 
@@ -605,6 +608,12 @@ load_service()
 
 
 	config_get auto_set_dnsmasq "$section" "auto_set_dnsmasq" "1"
 	config_get auto_set_dnsmasq "$section" "auto_set_dnsmasq" "1"
 
 
+	config_get ipset_name "$section" "ipset_name" ""
+	[ -z "$ipset_name" ] || conf_append "ipset" "$ipset_name"
+
+	config_get nftset_name "$section" "nftset_name" ""
+	[ -z "$nftset_name" ] || conf_append "nftset" "$nftset_name"
+
 	config_get ipset_no_speed "$section" "ipset_no_speed" ""
 	config_get ipset_no_speed "$section" "ipset_no_speed" ""
 	[ -z "$ipset_no_speed" ] || conf_append "ipset-no-speed" "$ipset_no_speed"
 	[ -z "$ipset_no_speed" ] || conf_append "ipset-no-speed" "$ipset_no_speed"
 
 

+ 8 - 3
src/dns_client.c

@@ -612,14 +612,18 @@ static struct dns_server_group *_dns_client_get_dnsserver_group(const char *grou
 	struct dns_server_group *group = _dns_client_get_group(group_name);
 	struct dns_server_group *group = _dns_client_get_group(group_name);
 
 
 	if (group == NULL) {
 	if (group == NULL) {
-		group = client.default_group;
+		goto use_default;
 	} else {
 	} else {
 		if (list_empty(&group->head)) {
 		if (list_empty(&group->head)) {
-			group = client.default_group;
+			tlog(TLOG_INFO, "group %s not exist, use default group.", group_name);
+			goto use_default;
 		}
 		}
 	}
 	}
 
 
 	return group;
 	return group;
+
+use_default:
+	return client.default_group;
 }
 }
 
 
 /* add server to group */
 /* add server to group */
@@ -1228,7 +1232,8 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
 		snprintf(ifname, sizeof(ifname), "@%s", flags->ifname);
 		snprintf(ifname, sizeof(ifname), "@%s", flags->ifname);
 	}
 	}
 
 
-	tlog(TLOG_INFO, "add server %s:%d%s, type: %s", server_ip, port, ifname, _dns_server_get_type_string(server_info->type));
+	tlog(TLOG_INFO, "add server %s:%d%s, type: %s", server_ip, port, ifname,
+		 _dns_server_get_type_string(server_info->type));
 
 
 	return 0;
 	return 0;
 errout:
 errout:

+ 148 - 61
src/dns_conf.c

@@ -163,8 +163,10 @@ int dns_conf_force_AAAA_SOA;
 int dns_conf_force_no_cname;
 int dns_conf_force_no_cname;
 int dns_conf_ipset_timeout_enable;
 int dns_conf_ipset_timeout_enable;
 struct dns_ipset_names dns_conf_ipset_no_speed;
 struct dns_ipset_names dns_conf_ipset_no_speed;
+struct dns_ipset_names dns_conf_ipset;
 int dns_conf_nftset_timeout_enable;
 int dns_conf_nftset_timeout_enable;
 struct dns_nftset_names dns_conf_nftset_no_speed;
 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_nftset_debug_enable;
 int dns_conf_mdns_lookup;
 int dns_conf_mdns_lookup;
 
 
@@ -318,10 +320,15 @@ static int _get_domain(char *value, char *domain, int max_domain_size, char **pt
 	}
 	}
 
 
 	size_t domain_len = max_domain_size;
 	size_t domain_len = max_domain_size;
-	domain_len = utf8_to_punycode(begin, len, domain, domain_len);
-	if (domain_len <= 0) {
-		tlog(TLOG_ERROR, "domain name %s invalid", value);
-		goto errout;
+	if (strncmp(begin, "domain-set:", sizeof("domain-set:") - 1) == 0) {
+		memcpy(domain, begin, len);
+		domain_len = len;
+	} else {
+		domain_len = utf8_to_punycode(begin, len, domain, domain_len);
+		if (domain_len <= 0) {
+			tlog(TLOG_ERROR, "domain name %s invalid", value);
+			goto errout;
+		}
 	}
 	}
 
 
 	domain[domain_len] = '\0';
 	domain[domain_len] = '\0';
@@ -887,21 +894,28 @@ static int _config_set_rule_each_from_list(const char *file, set_rule_add_func c
 	return ret;
 	return ret;
 }
 }
 
 
-static int _config_domain_rule_set_each(const char *domain_set, set_rule_add_func callback, void *priv)
+static struct dns_domain_set_name_list *_config_get_domain_set_name_list(const char *name)
 {
 {
-	struct dns_domain_set_name_list *set_name_list = NULL;
-	struct dns_domain_set_name *set_name_item = NULL;
-
 	uint32_t key = 0;
 	uint32_t key = 0;
+	struct dns_domain_set_name_list *set_name_list = NULL;
 
 
-	key = hash_string(domain_set);
+	key = hash_string(name);
 	hash_for_each_possible(dns_domain_set_name_table.names, set_name_list, node, key)
 	hash_for_each_possible(dns_domain_set_name_table.names, set_name_list, node, key)
 	{
 	{
-		if (strcmp(set_name_list->name, domain_set) == 0) {
-			break;
+		if (strcmp(set_name_list->name, name) == 0) {
+			return set_name_list;
 		}
 		}
 	}
 	}
 
 
+	return NULL;
+}
+
+static int _config_domain_rule_set_each(const char *domain_set, set_rule_add_func callback, void *priv)
+{
+	struct dns_domain_set_name_list *set_name_list = NULL;
+	struct dns_domain_set_name *set_name_item = NULL;
+
+	set_name_list = _config_get_domain_set_name_list(domain_set);
 	if (set_name_list == NULL) {
 	if (set_name_list == NULL) {
 		tlog(TLOG_WARN, "domain set %s not found.", domain_set);
 		tlog(TLOG_WARN, "domain set %s not found.", domain_set);
 		return -1;
 		return -1;
@@ -1223,6 +1237,7 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname)
 	char *copied_name = NULL;
 	char *copied_name = NULL;
 	enum domain_rule type = 0;
 	enum domain_rule type = 0;
 	int ignore_flag = 0;
 	int ignore_flag = 0;
+	int ret = -1;
 
 
 	copied_name = strdup(ipsetname);
 	copied_name = strdup(ipsetname);
 
 
@@ -1272,6 +1287,7 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname)
 		ipset_rule = NULL;
 		ipset_rule = NULL;
 	}
 	}
 
 
+	ret = 0;
 	goto clear;
 	goto clear;
 
 
 errout:
 errout:
@@ -1286,42 +1302,18 @@ clear:
 		free(copied_name);
 		free(copied_name);
 	}
 	}
 
 
-	return 0;
-}
-
-static int _config_ipset(void *data, int argc, char *argv[])
-{
-	char domain[DNS_MAX_CONF_CNAME_LEN];
-	char *value = argv[1];
-
-	if (argc <= 1) {
-		goto errout;
-	}
-
-	if (_get_domain(value, domain, DNS_MAX_CONF_CNAME_LEN, &value) != 0) {
-		goto errout;
-	}
-
-	return _conf_domain_rule_ipset(domain, value);
-errout:
-	tlog(TLOG_ERROR, "add ipset %s failed", value);
-	return 0;
+	return ret;
 }
 }
 
 
-static int _config_ipset_no_speed(void *data, int argc, char *argv[])
+static int _config_ipset_setvalue(struct dns_ipset_names *ipsets, const char *ipsetvalue)
 {
 {
-	char *ipsetname = argv[1];
 	char *copied_name = NULL;
 	char *copied_name = NULL;
 	const char *ipset = NULL;
 	const char *ipset = NULL;
 	struct dns_ipset_rule *ipset_rule_array[2] = {NULL, NULL};
 	struct dns_ipset_rule *ipset_rule_array[2] = {NULL, NULL};
 	char *ipset_rule_enable_array[2] = {NULL, NULL};
 	char *ipset_rule_enable_array[2] = {NULL, NULL};
 	int ipset_num = 0;
 	int ipset_num = 0;
 
 
-	if (argc <= 1) {
-		goto errout;
-	}
-
-	copied_name = strdup(ipsetname);
+	copied_name = strdup(ipsetvalue);
 
 
 	if (copied_name == NULL) {
 	if (copied_name == NULL) {
 		goto errout;
 		goto errout;
@@ -1330,12 +1322,12 @@ static int _config_ipset_no_speed(void *data, int argc, char *argv[])
 	for (char *tok = strtok(copied_name, ","); tok && ipset_num <= 2; tok = strtok(NULL, ",")) {
 	for (char *tok = strtok(copied_name, ","); tok && ipset_num <= 2; tok = strtok(NULL, ",")) {
 		if (tok[0] == '#') {
 		if (tok[0] == '#') {
 			if (strncmp(tok, "#6:", 3U) == 0) {
 			if (strncmp(tok, "#6:", 3U) == 0) {
-				ipset_rule_array[ipset_num] = &dns_conf_ipset_no_speed.ipv6;
-				ipset_rule_enable_array[ipset_num] = &dns_conf_ipset_no_speed.ipv6_enable;
+				ipset_rule_array[ipset_num] = &ipsets->ipv6;
+				ipset_rule_enable_array[ipset_num] = &ipsets->ipv6_enable;
 				ipset_num++;
 				ipset_num++;
 			} else if (strncmp(tok, "#4:", 3U) == 0) {
 			} else if (strncmp(tok, "#4:", 3U) == 0) {
-				ipset_rule_array[ipset_num] = &dns_conf_ipset_no_speed.ipv4;
-				ipset_rule_enable_array[ipset_num] = &dns_conf_ipset_no_speed.ipv4_enable;
+				ipset_rule_array[ipset_num] = &ipsets->ipv4;
+				ipset_rule_enable_array[ipset_num] = &ipsets->ipv4_enable;
 				ipset_num++;
 				ipset_num++;
 			} else {
 			} else {
 				goto errout;
 				goto errout;
@@ -1344,11 +1336,9 @@ static int _config_ipset_no_speed(void *data, int argc, char *argv[])
 		}
 		}
 
 
 		if (ipset_num == 0) {
 		if (ipset_num == 0) {
-			ipset_rule_array[1] = &dns_conf_ipset_no_speed.ipv6;
-			ipset_rule_enable_array[1] = &dns_conf_ipset_no_speed.ipv6_enable;
-			ipset_rule_array[0] = &dns_conf_ipset_no_speed.ipv4;
-			ipset_rule_enable_array[0] = &dns_conf_ipset_no_speed.ipv4_enable;
-			ipset_num = 2;
+			ipset_rule_array[0] = &ipsets->inet;
+			ipset_rule_enable_array[0] = &ipsets->inet_enable;
+			ipset_num = 1;
 		}
 		}
 
 
 		if (strncmp(tok, "-", 1) == 0) {
 		if (strncmp(tok, "-", 1) == 0) {
@@ -1376,6 +1366,57 @@ errout:
 		free(copied_name);
 		free(copied_name);
 	}
 	}
 
 
+	return 0;
+}
+
+static int _config_ipset(void *data, int argc, char *argv[])
+{
+	char domain[DNS_MAX_CONF_CNAME_LEN];
+	char *value = argv[1];
+	int ret = 0;
+
+	if (argc <= 1) {
+		goto errout;
+	}
+
+	if (_get_domain(value, domain, DNS_MAX_CONF_CNAME_LEN, &value) != 0) {
+		if (strstr(value, "/")) {
+			goto errout;
+		}
+
+		if (_config_ipset_setvalue(&dns_conf_ipset, value) != 0) {
+			ret = -1;
+			goto errout;
+		}
+
+		return 0;
+	}
+
+	ret = _conf_domain_rule_ipset(domain, value);
+	if (ret != 0) {
+		goto errout;
+	}
+
+	return 0;
+errout:
+	tlog(TLOG_WARN, "add ipset %s failed.", value);
+	return ret;
+}
+
+static int _config_ipset_no_speed(void *data, int argc, char *argv[])
+{
+	char *ipsetname = argv[1];
+
+	if (argc <= 1) {
+		goto errout;
+	}
+
+	if (_config_ipset_setvalue(&dns_conf_ipset_no_speed, ipsetname) != 0) {
+		goto errout;
+	}
+
+	return 0;
+errout:
 	tlog(TLOG_ERROR, "add ipset-no-speed %s failed", ipsetname);
 	tlog(TLOG_ERROR, "add ipset-no-speed %s failed", ipsetname);
 	return 0;
 	return 0;
 }
 }
@@ -1549,23 +1590,23 @@ errout:
 	return 0;
 	return 0;
 }
 }
 
 
-static int _config_nftset_no_speed(void *data, int argc, char *argv[])
+static int _config_nftset_setvalue(struct dns_nftset_names *nftsets, const char *nftsetvalue)
 {
 {
 	const struct dns_nftset_name *nftset = NULL;
 	const struct dns_nftset_name *nftset = NULL;
 	char *copied_name = NULL;
 	char *copied_name = NULL;
-	char *nftsetname = argv[1];
 	int nftset_num = 0;
 	int nftset_num = 0;
 	char *setname = NULL;
 	char *setname = NULL;
 	char *tablename = NULL;
 	char *tablename = NULL;
 	char *family = NULL;
 	char *family = NULL;
+	int ret = -1;
 	struct dns_nftset_rule *nftset_rule_array[2] = {NULL, NULL};
 	struct dns_nftset_rule *nftset_rule_array[2] = {NULL, NULL};
 	char *nftset_rule_enable_array[2] = {NULL, NULL};
 	char *nftset_rule_enable_array[2] = {NULL, NULL};
 
 
-	if (argc <= 1) {
+	if (nftsetvalue == NULL) {
 		goto errout;
 		goto errout;
 	}
 	}
 
 
-	copied_name = strdup(nftsetname);
+	copied_name = strdup(nftsetvalue);
 
 
 	if (copied_name == NULL) {
 	if (copied_name == NULL) {
 		goto errout;
 		goto errout;
@@ -1576,13 +1617,13 @@ static int _config_nftset_no_speed(void *data, int argc, char *argv[])
 		char *tok_set = NULL;
 		char *tok_set = NULL;
 
 
 		if (strncmp(tok, "#4:", 3U) == 0) {
 		if (strncmp(tok, "#4:", 3U) == 0) {
-			dns_conf_nftset_no_speed.ip_enable = 1;
-			nftset_rule_array[nftset_num] = &dns_conf_nftset_no_speed.ip;
-			nftset_rule_enable_array[nftset_num] = &dns_conf_nftset_no_speed.ip_enable;
+			nftsets->ip_enable = 1;
+			nftset_rule_array[nftset_num] = &nftsets->ip;
+			nftset_rule_enable_array[nftset_num] = &nftsets->ip_enable;
 			nftset_num++;
 			nftset_num++;
 		} else if (strncmp(tok, "#6:", 3U) == 0) {
 		} else if (strncmp(tok, "#6:", 3U) == 0) {
-			nftset_rule_enable_array[nftset_num] = &dns_conf_nftset_no_speed.ip6_enable;
-			nftset_rule_array[nftset_num] = &dns_conf_nftset_no_speed.ip6;
+			nftset_rule_enable_array[nftset_num] = &nftsets->ip6_enable;
+			nftset_rule_array[nftset_num] = &nftsets->ip6;
 			nftset_num++;
 			nftset_num++;
 		} else if (strncmp(tok, "-", 2U) == 0) {
 		} else if (strncmp(tok, "-", 2U) == 0) {
 			continue;
 			continue;
@@ -1594,10 +1635,10 @@ static int _config_nftset_no_speed(void *data, int argc, char *argv[])
 		tok_set = tok + 3;
 		tok_set = tok + 3;
 
 
 		if (nftset_num == 0) {
 		if (nftset_num == 0) {
-			nftset_rule_array[0] = &dns_conf_nftset_no_speed.ip;
-			nftset_rule_enable_array[0] = &dns_conf_nftset_no_speed.ip_enable;
-			nftset_rule_array[1] = &dns_conf_nftset_no_speed.ip6;
-			nftset_rule_enable_array[1] = &dns_conf_nftset_no_speed.ip6_enable;
+			nftset_rule_array[0] = &nftsets->ip;
+			nftset_rule_enable_array[0] = &nftsets->ip_enable;
+			nftset_rule_array[1] = &nftsets->ip6;
+			nftset_rule_enable_array[1] = &nftsets->ip6_enable;
 			nftset_num = 2;
 			nftset_num = 2;
 		}
 		}
 
 
@@ -1636,15 +1677,34 @@ static int _config_nftset_no_speed(void *data, int argc, char *argv[])
 		nftset_num = 0;
 		nftset_num = 0;
 	}
 	}
 
 
+	ret = 0;
 	goto clear;
 	goto clear;
 
 
 errout:
 errout:
-	tlog(TLOG_ERROR, "add nftset %s failed", nftsetname);
+	ret = -1;
 clear:
 clear:
 	if (copied_name) {
 	if (copied_name) {
 		free(copied_name);
 		free(copied_name);
 	}
 	}
 
 
+	return ret;
+}
+
+static int _config_nftset_no_speed(void *data, int argc, char *argv[])
+{
+	char *nftsetname = argv[1];
+
+	if (argc <= 1) {
+		goto errout;
+	}
+
+	if (_config_nftset_setvalue(&dns_conf_nftset_no_speed, nftsetname) != 0) {
+		goto errout;
+	}
+
+	return 0;
+errout:
+	tlog(TLOG_ERROR, "add nftset %s failed", nftsetname);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2286,6 +2346,8 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
 		{"no-dualstack-selection", no_argument, NULL, 'D'},
 		{"no-dualstack-selection", no_argument, NULL, 'D'},
 		{"no-ip-alias", no_argument, NULL, 'a'},
 		{"no-ip-alias", no_argument, NULL, 'a'},
 		{"force-aaaa-soa", no_argument, NULL, 'F'},
 		{"force-aaaa-soa", no_argument, NULL, 'F'},
+		{"no-serve-expired", no_argument, NULL, 253},
+		{"force-https-soa", no_argument, NULL, 254},
 		{"ipset", required_argument, NULL, 255},
 		{"ipset", required_argument, NULL, 255},
 		{"nftset", required_argument, NULL, 256},
 		{"nftset", required_argument, NULL, 256},
 		{NULL, no_argument, NULL, 0}
 		{NULL, no_argument, NULL, 0}
@@ -2375,12 +2437,26 @@ 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 253: {
+			server_flag |= BIND_FLAG_NO_SERVE_EXPIRED;
+			break;
+		}
+		case 254: {
+			server_flag |= BIND_FLAG_FORCE_HTTPS_SOA;
+			break;
+		}
 		case 255: {
 		case 255: {
 			_config_bind_ip_parser_ipset(bind_ip, &server_flag, optarg);
 			_config_bind_ip_parser_ipset(bind_ip, &server_flag, optarg);
+			server_flag |= BIND_FLAG_NO_DUALSTACK_SELECTION;
+			server_flag |= BIND_FLAG_NO_PREFETCH;
+			server_flag |= BIND_FLAG_NO_SERVE_EXPIRED;
 			break;
 			break;
 		}
 		}
 		case 256: {
 		case 256: {
 			_config_bind_ip_parser_nftset(bind_ip, &server_flag, optarg);
 			_config_bind_ip_parser_nftset(bind_ip, &server_flag, optarg);
+			server_flag |= BIND_FLAG_NO_DUALSTACK_SELECTION;
+			server_flag |= BIND_FLAG_NO_PREFETCH;
+			server_flag |= BIND_FLAG_NO_SERVE_EXPIRED;
 			break;
 			break;
 		}
 		}
 		default:
 		default:
@@ -3665,6 +3741,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
 		{"ipset", required_argument, NULL, 'p'},
 		{"ipset", required_argument, NULL, 'p'},
 		{"nftset", required_argument, NULL, 't'},
 		{"nftset", required_argument, NULL, 't'},
 		{"nameserver", required_argument, NULL, 'n'},
 		{"nameserver", required_argument, NULL, 'n'},
+		{"group", required_argument, NULL, 'n'},
 		{"dualstack-ip-selection", required_argument, NULL, 'd'},
 		{"dualstack-ip-selection", required_argument, NULL, 'd'},
 		{"cname", required_argument, NULL, 'A'},
 		{"cname", required_argument, NULL, 'A'},
 		{"rr-ttl", required_argument, NULL, 251},
 		{"rr-ttl", required_argument, NULL, 251},
@@ -3687,6 +3764,16 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
 		goto errout;
 		goto errout;
 	}
 	}
 
 
+	/* check domain set exists. */
+	if (strncmp(domain, "domain-set:", sizeof("domain-set:") - 1) == 0) {
+		const char *set_name = domain + sizeof("domain-set:") - 1;
+		struct dns_domain_set_name_list *name = _config_get_domain_set_name_list(set_name);
+		if (name == NULL) {
+			tlog(TLOG_ERROR, "domain set '%s' not found.", set_name);
+			goto errout;
+		}
+	}
+
 	/* process extra options */
 	/* process extra options */
 	optind = 1;
 	optind = 1;
 	while (1) {
 	while (1) {

+ 7 - 0
src/dns_conf.h

@@ -148,6 +148,9 @@ typedef enum {
 #define BIND_FLAG_NO_RULE_CNAME (1 << 9)
 #define BIND_FLAG_NO_RULE_CNAME (1 << 9)
 #define BIND_FLAG_NO_RULE_NFTSET (1 << 10)
 #define BIND_FLAG_NO_RULE_NFTSET (1 << 10)
 #define BIND_FLAG_NO_IP_ALIAS (1 << 11)
 #define BIND_FLAG_NO_IP_ALIAS (1 << 11)
+#define BIND_FLAG_NO_PREFETCH (1 << 12)
+#define BIND_FLAG_FORCE_HTTPS_SOA (1 << 13)
+#define BIND_FLAG_NO_SERVE_EXPIRED (1 << 14)
 
 
 enum response_mode_type {
 enum response_mode_type {
 	DNS_RESPONSE_MODE_FIRST_PING_IP = 0,
 	DNS_RESPONSE_MODE_FIRST_PING_IP = 0,
@@ -189,12 +192,15 @@ struct dns_ipset_rule {
 };
 };
 
 
 struct dns_ipset_names {
 struct dns_ipset_names {
+	char inet_enable;
 	char ipv4_enable;
 	char ipv4_enable;
 	char ipv6_enable;
 	char ipv6_enable;
+	struct dns_ipset_rule inet;
 	struct dns_ipset_rule ipv4;
 	struct dns_ipset_rule ipv4;
 	struct dns_ipset_rule ipv6;
 	struct dns_ipset_rule ipv6;
 };
 };
 extern struct dns_ipset_names dns_conf_ipset_no_speed;
 extern struct dns_ipset_names dns_conf_ipset_no_speed;
+extern struct dns_ipset_names dns_conf_ipset;
 
 
 struct dns_cname_rule {
 struct dns_cname_rule {
 	struct dns_rule head;
 	struct dns_rule head;
@@ -231,6 +237,7 @@ struct dns_nftset_names {
 	struct dns_nftset_rule ip6;
 	struct dns_nftset_rule ip6;
 };
 };
 extern struct dns_nftset_names dns_conf_nftset_no_speed;
 extern struct dns_nftset_names dns_conf_nftset_no_speed;
+extern struct dns_nftset_names dns_conf_nftset;
 
 
 struct dns_domain_rule {
 struct dns_domain_rule {
 	struct dns_rule head;
 	struct dns_rule head;

+ 38 - 1
src/dns_server.c

@@ -1889,6 +1889,14 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 		if (ipset_rule == NULL) {
 		if (ipset_rule == NULL) {
 			ipset_rule = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET);
 			ipset_rule = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET);
 		}
 		}
+
+		if (ipset_rule == NULL && dns_conf_ipset.inet_enable) {
+			ipset_rule = &dns_conf_ipset.inet;
+		}
+
+		if (ipset_rule == NULL && check_no_speed_rule && dns_conf_ipset_no_speed.inet_enable) {
+			ipset_rule_v4 = &dns_conf_ipset_no_speed.inet;
+		}
 	}
 	}
 
 
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
 	if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
@@ -1897,7 +1905,11 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 			ipset_rule_v4 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET_IPV4);
 			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_v4 == NULL && ipset_rule == NULL && dns_conf_ipset.ipv4_enable) {
+			ipset_rule_v4 = &dns_conf_ipset.ipv4;
+		}
+
+		if (ipset_rule_v4 == 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;
 		}
 		}
 	}
 	}
@@ -1908,6 +1920,10 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 			ipset_rule_v6 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET_IPV6);
 			ipset_rule_v6 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET_IPV6);
 		}
 		}
 
 
+		if (ipset_rule_v6 == NULL && ipset_rule == NULL && dns_conf_ipset.ipv6_enable) {
+			ipset_rule_v6 = &dns_conf_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;
 		}
 		}
@@ -1919,6 +1935,10 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 			nftset_ip = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_NFTSET_IP);
 			nftset_ip = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_NFTSET_IP);
 		}
 		}
 
 
+		if (nftset_ip == NULL && dns_conf_nftset.ip_enable) {
+			nftset_ip = &dns_conf_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;
 		}
 		}
@@ -1931,6 +1951,10 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
 			nftset_ip6 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_NFTSET_IP6);
 			nftset_ip6 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_NFTSET_IP6);
 		}
 		}
 
 
+		if (nftset_ip6 == NULL && dns_conf_nftset.ip6_enable) {
+			nftset_ip6 = &dns_conf_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;
 		}
 		}
@@ -4522,6 +4546,19 @@ static int _dns_server_pre_process_server_flags(struct dns_request *request)
 		request->no_ipalias = 1;
 		request->no_ipalias = 1;
 	}
 	}
 
 
+	if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_PREFETCH) == 0) {
+		request->prefetch_flags |= PREFETCH_FLAGS_NOPREFETCH;
+	}
+
+	if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_SERVE_EXPIRED) == 0) {
+		request->no_serve_expired = 1;
+	}
+
+	if (_dns_server_has_bind_flag(request, BIND_FLAG_FORCE_HTTPS_SOA) == 0) {
+		_dns_server_reply_SOA(DNS_RC_NOERROR, request);
+		return 0;
+	}
+
 	return -1;
 	return -1;
 }
 }
 
 

+ 5 - 0
src/tlog.c

@@ -716,6 +716,11 @@ static int _tlog_early_print(struct tlog_info_inter *info_inter, const char *for
         out_len++;
         out_len++;
     }
     }
 
 
+    if (out_len + 1 < sizeof(log_buf) - out_len - 1) {
+        log_buf[out_len] = '\0';
+        out_len++;
+    }
+
     if (tlog.early_print_output != NULL) {
     if (tlog.early_print_output != NULL) {
         len = tlog.early_print_output(&info_inter->info, log_buf, out_len, tlog.early_print_userptr);
         len = tlog.early_print_output(&info_inter->info, log_buf, out_len, tlog.early_print_userptr);
         if (tlog.early_print_with_screen == 0) {
         if (tlog.early_print_with_screen == 0) {