Bläddra i källkod

domain-set: keep domain rules orders

Nick Peng 2 år sedan
förälder
incheckning
c6ac69a8d8
6 ändrade filer med 156 tillägg och 180 borttagningar
  1. 1 1
      ReadMe.md
  2. 1 1
      ReadMe_en.md
  3. 1 0
      etc/smartdns/smartdns.conf
  4. 142 166
      src/dns_conf.c
  5. 10 11
      src/dns_conf.h
  6. 1 1
      src/smartdns.c

+ 1 - 1
ReadMe.md

@@ -608,7 +608,7 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
 | nftset | 域名 nftset | 无 | nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]],-表示忽略;ipv4 地址的 family 只支持 inet 和 ip;ipv6 地址的 family 只支持 inet 和 ip6;由于 nft 限制,两种地址只能分开存放于两个 set 中。| nftset /www.example.com/#4:inet#tab#dns4,#6:- |
 | nftset-timeout | 设置 nftset 超时功能启用  | no | [yes\|no] | nftset-timeout yes |
 | nftset-debug | 设置 nftset 调试功能启用  | no | [yes\|no] | nftset-debug yes |
-| domain-rules | 设置域名规则 | 无 | domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]:测速模式,参考 speed-check-mode 配置<br />[-a\|-address]:参考 address 配置<br />[-n\|-nameserver]:参考 nameserver 配置<br />[-p\|-ipset]:参考ipset配置<br />[-t\|-nftset]:参考nftset配置<br />[-d\|-dualstack-ip-selection]:参考 dualstack-ip-selection<br /> [-no-serve-expired]:禁用过期缓存 | domain-rules /www.example.com/ -speed-check-mode none |
+| domain-rules | 设置域名规则 | 无 | domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]:测速模式,参考 speed-check-mode 配置<br />[-a\|-address]:参考 address 配置<br />[-n\|-nameserver]:参考 nameserver 配置<br />[-p\|-ipset]:参考ipset配置<br />[-t\|-nftset]:参考nftset配置<br />[-d\|-dualstack-ip-selection]:参考 dualstack-ip-selection<br /> [-no-serve-expired]:禁用过期缓存<br />[-delete]:删除对应的规则 | domain-rules /www.example.com/ -speed-check-mode none |
 | domain-set | 设置域名集合 | 无 | domain-set [options...]<br />[-n\|-name]:域名集合名称 <br />[-t\|-type]:域名集合类型,当前仅支持list,格式为域名列表,一行一个域名。<br />[-f\|-file]:域名集合文件路径。<br /> 选项需要配合address, nameserver, ipset, nftset等需要指定域名的地方使用,使用方式为 /domain-set:[name]/| domain-set -name set -type list -file /path/to/list <br /> address /domain-set:set/1.2.4.8 |
 | bogus-nxdomain | 假冒 IP 地址过滤 | 无 | [ip/subnet],可重复 | bogus-nxdomain 1.2.3.4/16 |
 | ignore-ip | 忽略 IP 地址 | 无 | [ip/subnet],可重复 | ignore-ip 1.2.3.4/16 |

+ 1 - 1
ReadMe_en.md

@@ -571,7 +571,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
 |nftset|Domain nftset|None|nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]], `-` to ignore; the valid families are inet and ip for ipv4 addresses while the valid ones are inet and ip6 for ipv6 addresses; due to the limitation of nft, two types of addresses have to be stored in two sets|nftset /www.example.com/#4:inet#tab#dns4,#6:-
 |nftset-timeout|nftset timeout enable|no|[yes\|no]|nftset-timeout yes
 |nftset-debug|nftset debug enable|no|[yes\|no]|nftset-debug yes
-|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]: set speed check mode,same as parameter speed-check-mode<br />[-a\|-address]: same as  parameter `address` <br />[-n\|-nameserver]: same as parameter `nameserver`<br />[-p\|-ipset]: same as parameter `nftset`<br />[-t\|-nftset]: same as parameter `nftset`<br />[-d\|-dualstack-ip-selection]: same as parameter `dualstack-ip-selection`<br />  [-no-serve-expired]:disable serve expired|domain-rules /www.example.com/ -speed-check-mode none
+|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]: set speed check mode,same as parameter speed-check-mode<br />[-a\|-address]: same as  parameter `address` <br />[-n\|-nameserver]: same as parameter `nameserver`<br />[-p\|-ipset]: same as parameter `nftset`<br />[-t\|-nftset]: same as parameter `nftset`<br />[-d\|-dualstack-ip-selection]: same as parameter `dualstack-ip-selection`<br />  [-no-serve-expired]:disable serve expired<br />[-delete]:delete rule|domain-rules /www.example.com/ -speed-check-mode none
 | domain-set | collection of domains|None| domain-set [options...]<br />[-n\|-name]:name of set <br />[-t\|-type] [list]: set type, only support list, one domain per line <br />[-f\|-file]:file path of domain set<br /> used with address, nameserver, ipset, nftset, example: /domain-set:[name]/ | domain-set -name set -type list -file /path/to/list <br /> address /domain-set:set/1.2.4.8 |
 |bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 1.2.3.4/16
 |ignore-ip|ignore ip address|None|[ip/subnet], Repeatable| ignore-ip 1.2.3.4/16

+ 1 - 0
etc/smartdns/smartdns.conf

@@ -259,6 +259,7 @@ log-level info
 #   [-t] -nftset [nftset|-]: same as nftset option
 #   [-d] -dualstack-ip-selection [yes|no]: same as dualstack-ip-selection option
 #   -no-serve-expired: ignore expired domain
+#   -delete: delete domain rule
 
 # collection of domains 
 # the domain-set can be used with /domain/ for address, nameserver, ipset, etc.

+ 142 - 166
src/dns_conf.c

@@ -47,7 +47,6 @@ static struct dns_nftset_table dns_nftset_table;
 
 struct dns_qtype_soa_table dns_qtype_soa_table;
 
-struct dns_domain_set_rule_table dns_domain_set_rule_table;
 struct dns_domain_set_name_table dns_domain_set_name_table;
 
 /* dns groups */
@@ -621,9 +620,8 @@ errout:
 	return -1;
 }
 
-static int _config_domain_iter_free(void *data, const unsigned char *key, uint32_t key_len, void *value)
+static int _config_domain_rule_free(struct dns_domain_rule *domain_rule)
 {
-	struct dns_domain_rule *domain_rule = value;
 	int i = 0;
 
 	if (domain_rule == NULL) {
@@ -643,6 +641,12 @@ static int _config_domain_iter_free(void *data, const unsigned char *key, uint32
 	return 0;
 }
 
+static int _config_domain_iter_free(void *data, const unsigned char *key, uint32_t key_len, void *value)
+{
+	struct dns_domain_rule *domain_rule = value;
+	return _config_domain_rule_free(domain_rule);
+}
+
 static void _config_domain_destroy(void)
 {
 	art_iter(&dns_conf_domain_rule, _config_domain_iter_free, NULL);
@@ -663,71 +667,90 @@ static void _config_address_destroy(radix_node_t *node, void *cbctx)
 	node->data = NULL;
 }
 
-static int _config_domain_set_rule_add_ext(const char *set_name, enum domain_rule type, void *rule, unsigned int flags,
-										   int is_clear_flag)
+typedef int (*domain_set_rule_add_func)(const char *domain, void *priv);
+static int _config_domain_rule_each_from_list(const char *file, domain_set_rule_add_func callback, void *priv)
 {
-	struct dns_domain_set_rule *set_rule = NULL;
-	struct dns_domain_set_rule_list *set_rule_list = NULL;
-	uint32_t key = 0;
+	FILE *fp = NULL;
+	char line[MAX_LINE_LEN];
+	char domain[DNS_MAX_CNAME_LEN];
+	int ret = 0;
+	int line_no = 0;
+	int filed_num = 0;
 
-	if (set_name == NULL) {
-		return -1;
+	fp = fopen(file, "r");
+	if (fp == NULL) {
+		tlog(TLOG_WARN, "open file %s error, %s", file, strerror(errno));
+		return 0;
 	}
 
-	set_rule = malloc(sizeof(struct dns_domain_set_rule));
-	if (set_rule == NULL) {
-		goto errout;
-	}
-	memset(set_rule, 0, sizeof(struct dns_domain_set_rule));
+	line_no = 0;
+	while (fgets(line, MAX_LINE_LEN, fp)) {
+		line_no++;
+		filed_num = sscanf(line, "%256s", domain);
+		if (filed_num <= 0) {
+			continue;
+		}
 
-	set_rule->type = type;
-	set_rule->rule = rule;
-	set_rule->flags = flags;
-	set_rule->is_clear_flag = is_clear_flag;
+		if (domain[0] == '#' || domain[0] == '\n') {
+			continue;
+		}
 
-	if (rule) {
-		_dns_rule_get(rule);
+		ret = callback(domain, priv);
+		if (ret != 0) {
+			tlog(TLOG_WARN, "process file %s failed at line %d.", file, line_no);
+			continue;
+		}
 	}
 
-	key = hash_string(set_name);
-	hash_for_each_possible(dns_domain_set_rule_table.rule_list, set_rule_list, node, key)
+	fclose(fp);
+	return ret;
+}
+
+static int _config_domain_rule_set_each(const char *domain_set, domain_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;
+
+	uint32_t key = 0;
+
+	key = hash_string(domain_set);
+	hash_for_each_possible(dns_domain_set_name_table.names, set_name_list, node, key)
 	{
-		if (strncmp(set_rule_list->domain_set, set_name, DNS_MAX_CNAME_LEN) == 0) {
+		if (strcmp(set_name_list->name, domain_set) == 0) {
 			break;
 		}
 	}
 
-	if (set_rule_list == NULL) {
-		set_rule_list = malloc(sizeof(struct dns_domain_set_rule_list));
-		if (set_rule_list == NULL) {
-			goto errout;
-		}
-		memset(set_rule_list, 0, sizeof(struct dns_domain_set_rule_list));
-		INIT_LIST_HEAD(&set_rule_list->domain_rule_list);
-		safe_strncpy(set_rule_list->domain_set, set_name, DNS_MAX_CNAME_LEN);
-		hash_add(dns_domain_set_rule_table.rule_list, &set_rule_list->node, key);
+	if (set_name_list == NULL) {
+		tlog(TLOG_WARN, "domain set %s not found.", domain_set);
+		return -1;
 	}
 
-	list_add_tail(&set_rule->list, &set_rule_list->domain_rule_list);
-	return 0;
-errout:
-	if (set_rule) {
-		free(set_rule);
+	list_for_each_entry(set_name_item, &set_name_list->set_name_list, list)
+	{
+		switch (set_name_item->type) {
+		case DNS_DOMAIN_SET_LIST:
+			_config_domain_rule_each_from_list(set_name_item->file, callback, priv);
+			break;
+		case DNS_DOMAIN_SET_GEOSITE:
+			break;
+		default:
+			tlog(TLOG_WARN, "domain set %s type %d not support.", set_name_list->name, set_name_item->type);
+			break;
+		}
 	}
-	return -1;
-}
 
-static int _config_domain_set_rule_flags(const char *set_name, unsigned int flags, int is_clear_flag)
-{
-	return _config_domain_set_rule_add_ext(set_name, DOMAIN_RULE_FLAGS, NULL, flags, is_clear_flag);
+	return 0;
 }
 
-static int _config_domain_set_rule_add(char *set_name, enum domain_rule type, void *rule)
+static int _config_domain_rule_add(const char *domain, enum domain_rule type, void *rule);
+static int _config_domain_rule_add_callback(const char *domain, void *priv)
 {
-	return _config_domain_set_rule_add_ext(set_name, type, rule, 0, 0);
+	struct dns_set_rule_add_callback_args *args = (struct dns_set_rule_add_callback_args *)priv;
+	return _config_domain_rule_add(domain, args->type, args->rule);
 }
 
-static int _config_domain_rule_add(char *domain, enum domain_rule type, void *rule)
+static int _config_domain_rule_add(const char *domain, enum domain_rule type, void *rule)
 {
 	struct dns_domain_rule *domain_rule = NULL;
 	struct dns_domain_rule *old_domain_rule = NULL;
@@ -744,7 +767,11 @@ static int _config_domain_rule_add(char *domain, enum domain_rule type, void *ru
 	}
 
 	if (strncmp(domain, "domain-set:", sizeof("domain-set:") - 1) == 0) {
-		return _config_domain_set_rule_add(domain + sizeof("domain-set:") - 1, type, rule);
+		struct dns_set_rule_add_callback_args args;
+		args.type = type;
+		args.rule = rule;
+		return _config_domain_rule_set_each(domain + sizeof("domain-set:") - 1, _config_domain_rule_add_callback,
+											&args);
 	}
 
 	reverse_string(domain_key, domain, len, 1);
@@ -780,7 +807,7 @@ static int _config_domain_rule_add(char *domain, enum domain_rule type, void *ru
 	if (add_domain_rule) {
 		old_domain_rule = art_insert(&dns_conf_domain_rule, (unsigned char *)domain_key, len, add_domain_rule);
 		if (old_domain_rule) {
-			free(old_domain_rule);
+			_config_domain_rule_free(old_domain_rule);
 		}
 	}
 
@@ -794,6 +821,53 @@ errout:
 	return -1;
 }
 
+static int _config_domain_rule_delete(const char *domain);
+static int _config_domain_rule_delete_callback(const char *domain, void *priv)
+{
+	return _config_domain_rule_delete(domain);
+}
+
+static int _config_domain_rule_delete(const char *domain)
+{
+	char domain_key[DNS_MAX_CONF_CNAME_LEN];
+	int len = 0;
+
+	/* Reverse string, for suffix match */
+	len = strlen(domain);
+	if (len >= (int)sizeof(domain_key)) {
+		tlog(TLOG_ERROR, "domain name %s too long", domain);
+		goto errout;
+	}
+
+	if (strncmp(domain, "domain-set:", sizeof("domain-set:") - 1) == 0) {
+		return _config_domain_rule_set_each(domain + sizeof("domain-set:") - 1, _config_domain_rule_delete_callback,
+											NULL);
+	}
+
+	reverse_string(domain_key, domain, len, 1);
+	domain_key[len] = '.';
+	len++;
+	domain_key[len] = 0;
+
+	/* delete existing rules */
+	void *rule = art_delete(&dns_conf_domain_rule, (unsigned char *)domain_key, len);
+	if (rule) {
+		_config_domain_rule_free(rule);
+	}
+
+	return 0;
+errout:
+	tlog(TLOG_ERROR, "delete domain %s rule failed", domain);
+	return -1;
+}
+
+static int _config_domain_rule_flag_set(const char *domain, unsigned int flag, unsigned int is_clear);
+static int _config_domain_rule_flag_callback(const char *domain, void *priv)
+{
+	struct dns_set_rule_flags_callback_args *args = (struct dns_set_rule_flags_callback_args *)priv;
+	return _config_domain_rule_flag_set(domain, args->flags, args->is_clear_flag);
+}
+
 static int _config_domain_rule_flag_set(const char *domain, unsigned int flag, unsigned int is_clear)
 {
 	struct dns_domain_rule *domain_rule = NULL;
@@ -805,7 +879,11 @@ static int _config_domain_rule_flag_set(const char *domain, unsigned int flag, u
 	int len = 0;
 
 	if (strncmp(domain, "domain-set:", sizeof("domain-set:") - 1) == 0) {
-		return _config_domain_set_rule_flags(domain + sizeof("domain-set:") - 1, flag, is_clear);
+		struct dns_set_rule_flags_callback_args args;
+		args.flags = flag;
+		args.is_clear_flag = is_clear;
+		return _config_domain_rule_set_each(domain + sizeof("domain-set:") - 1, _config_domain_rule_flag_callback,
+											&args);
 	}
 
 	len = strlen(domain);
@@ -848,7 +926,7 @@ static int _config_domain_rule_flag_set(const char *domain, unsigned int flag, u
 	if (add_domain_rule) {
 		old_domain_rule = art_insert(&dns_conf_domain_rule, (unsigned char *)domain_key, len, add_domain_rule);
 		if (old_domain_rule) {
-			free(old_domain_rule);
+			_config_domain_rule_free(old_domain_rule);
 		}
 	}
 
@@ -1843,29 +1921,6 @@ static void _config_domain_set_name_table_destroy(void)
 	}
 }
 
-static void _config_domain_set_rule_table_destroy(void)
-{
-	struct dns_domain_set_rule_list *set_rule_list = NULL;
-	struct hlist_node *tmp = NULL;
-	struct dns_domain_set_rule *set_rule = NULL;
-	struct dns_domain_set_rule *tmp1 = NULL;
-	unsigned long i = 0;
-
-	hash_for_each_safe(dns_domain_set_rule_table.rule_list, i, tmp, set_rule_list, node)
-	{
-		hlist_del_init(&set_rule_list->node);
-		list_for_each_entry_safe(set_rule, tmp1, &set_rule_list->domain_rule_list, list)
-		{
-			list_del(&set_rule->list);
-			if (set_rule->rule) {
-				_dns_rule_put(set_rule->rule);
-			}
-			free(set_rule);
-		}
-		free(set_rule_list);
-	}
-}
-
 static int _config_blacklist_ip(void *data, int argc, char *argv[])
 {
 	if (argc <= 1) {
@@ -2079,6 +2134,11 @@ static int _conf_domain_rule_no_serve_expired(const char *domain)
 	return _config_domain_rule_flag_set(domain, DOMAIN_FLAG_NO_SERVE_EXPIRED, 0);
 }
 
+static int _conf_domain_rule_delete(const char *domain)
+{
+	return _config_domain_rule_delete(domain);
+}
+
 static int _conf_domain_rules(void *data, int argc, char *argv[])
 {
 	int opt = 0;
@@ -2094,6 +2154,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
 		{"nameserver", required_argument, NULL, 'n'},
 		{"dualstack-ip-selection", required_argument, NULL, 'd'},
 		{"no-serve-expired", no_argument, NULL, 254},
+		{"delete", no_argument, NULL, 255},
 		{NULL, no_argument, NULL, 0}
 	};
 	/* clang-format on */
@@ -2198,6 +2259,14 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
 
 			break;
 		}
+		case 255: {
+			if (_conf_domain_rule_delete(domain) != 0) {
+				tlog(TLOG_ERROR, "delete domain rule failed.");
+				goto errout;
+			}
+
+			return 0;
+		}
 		default:
 			break;
 		}
@@ -2736,96 +2805,6 @@ int config_additional_file(void *data, int argc, char *argv[])
 	return load_conf(file_path, _config_item, _conf_printf);
 }
 
-static int _update_domain_set_from_list(const char *file, struct dns_domain_set_rule_list *set_rule_list)
-{
-	FILE *fp = NULL;
-	char line[MAX_LINE_LEN];
-	char domain[DNS_MAX_CNAME_LEN];
-	int ret = 0;
-	int line_no = 0;
-	int filed_num = 0;
-	struct dns_domain_set_rule *set_rule = NULL;
-
-	fp = fopen(file, "r");
-	if (fp == NULL) {
-		tlog(TLOG_WARN, "open file %s error, %s", file, strerror(errno));
-		return 0;
-	}
-
-	line_no = 0;
-	while (fgets(line, MAX_LINE_LEN, fp)) {
-		line_no++;
-		filed_num = sscanf(line, "%256s", domain);
-		if (filed_num <= 0) {
-			continue;
-		}
-
-		if (domain[0] == '#' || domain[0] == '\n') {
-			continue;
-		}
-
-		list_for_each_entry(set_rule, &set_rule_list->domain_rule_list, list)
-		{
-			if (set_rule->type == DOMAIN_RULE_FLAGS) {
-				ret = _config_domain_rule_flag_set(domain, set_rule->flags, set_rule->is_clear_flag);
-			} else {
-				ret = _config_domain_rule_add(domain, set_rule->type, set_rule->rule);
-			}
-
-			if (ret != 0) {
-				tlog(TLOG_WARN, "process file %s failed at line %d.", file, line_no);
-				continue;
-			}
-		}
-	}
-
-	fclose(fp);
-	return ret;
-}
-
-static int _update_domain_set(void)
-{
-	struct dns_domain_set_rule_list *set_rule_list = NULL;
-
-	struct dns_domain_set_name_list *set_name_list = NULL;
-	struct dns_domain_set_name *set_name_item = NULL;
-
-	unsigned long i = 0;
-	uint32_t key = 0;
-
-	hash_for_each(dns_domain_set_rule_table.rule_list, i, set_rule_list, node)
-	{
-		key = hash_string(set_rule_list->domain_set);
-		hash_for_each_possible(dns_domain_set_name_table.names, set_name_list, node, key)
-		{
-			if (strcmp(set_name_list->name, set_rule_list->domain_set) == 0) {
-				break;
-			}
-		}
-
-		if (set_name_list == NULL) {
-			tlog(TLOG_WARN, "domain set %s not found.", set_rule_list->domain_set);
-			continue;
-		}
-
-		list_for_each_entry(set_name_item, &set_name_list->set_name_list, list)
-		{
-			switch (set_name_item->type) {
-			case DNS_DOMAIN_SET_LIST:
-				_update_domain_set_from_list(set_name_item->file, set_rule_list);
-				break;
-			case DNS_DOMAIN_SET_GEOSITE:
-				break;
-			default:
-				tlog(TLOG_WARN, "domain set %s type %d not support.", set_name_list->name, set_name_item->type);
-				break;
-			}
-		}
-	}
-
-	return 0;
-}
-
 static int _dns_server_load_conf_init(void)
 {
 	dns_conf_address_rule.ipv4 = New_Radix();
@@ -2843,7 +2822,6 @@ static int _dns_server_load_conf_init(void)
 	hash_init(dns_group_table.group);
 	hash_init(dns_hosts_table.hosts);
 	hash_init(dns_ptr_table.ptr);
-	hash_init(dns_domain_set_rule_table.rule_list);
 	hash_init(dns_domain_set_name_table.names);
 
 	return 0;
@@ -2955,9 +2933,7 @@ static int _dns_conf_load_post(void)
 		safe_strncpy(dns_resolv_file, DNS_RESOLV_FILE, sizeof(dns_resolv_file));
 	}
 
-	_update_domain_set();
 	_config_domain_set_name_table_destroy();
-	_config_domain_set_rule_table_destroy();
 
 	return 0;
 }

+ 10 - 11
src/dns_conf.h

@@ -328,17 +328,6 @@ struct dns_domain_set_rule {
 	unsigned int is_clear_flag;
 };
 
-struct dns_domain_set_rule_list {
-	struct hlist_node node;
-	char domain_set[DNS_MAX_CNAME_LEN];
-	struct list_head domain_rule_list;
-};
-
-struct dns_domain_set_rule_table {
-	DECLARE_HASHTABLE(rule_list, 4);
-};
-extern struct dns_domain_set_rule_table dns_domain_set_rule_table;
-
 enum dns_domain_set_type {
 	DNS_DOMAIN_SET_LIST = 0,
 	DNS_DOMAIN_SET_GEOSITE = 1,
@@ -360,6 +349,16 @@ struct dns_domain_set_name_table {
 };
 extern struct dns_domain_set_name_table dns_domain_set_name_table;
 
+struct dns_set_rule_add_callback_args {
+	enum domain_rule type;
+	void *rule;
+};
+
+struct dns_set_rule_flags_callback_args {
+	unsigned int flags;
+	int is_clear_flag;
+};
+
 extern struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
 extern int dns_conf_bind_ip_num;
 

+ 1 - 1
src/smartdns.c

@@ -177,7 +177,7 @@ static int _smartdns_load_from_resolv(void)
 {
 	FILE *fp = NULL;
 	char line[MAX_LINE_LEN];
-	char key[MAX_KEY_LEN];
+	char key[MAX_KEY_LEN] = {0};
 	char value[MAX_LINE_LEN];
 	char ns_ip[DNS_MAX_IPLEN];
 	int port = PORT_NOT_DEFINED;