瀏覽代碼

ipset bugfix and add timeout feature

Nick Peng 6 年之前
父節點
當前提交
a1150a7ceb
共有 9 個文件被更改,包括 55 次插入18 次删除
  1. 1 0
      ReadMe.md
  2. 1 0
      ReadMe_zh-CN.md
  3. 3 0
      etc/smartdns/smartdns.conf
  4. 1 1
      src/dns_cache.c
  5. 3 0
      src/dns_conf.c
  6. 1 0
      src/dns_conf.h
  7. 20 8
      src/dns_server.c
  8. 24 8
      src/util.c
  9. 1 1
      src/util.h

+ 1 - 0
ReadMe.md

@@ -395,6 +395,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
 |server-tls|Upstream TLS DNS server|None|[IP][:port] [-blacklist-ip][-check-edns], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tls 8.8.8.8:853
 |address|Domain IP address|None|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-` for ignore, `#` for return SOA, `4` for IPV4, `6` for IPV6| address /www.example.com/1.2.3.4
 |ipset|Domain IPSet|None|ipset /domain/[ipset\|-], `-` for ignore|ipset /www.example.com/pass
+|ipset-timeout|ipset timeout enable|auto|[yes]|ipset-timeout yes
 |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
 |blacklist-ip|ip blacklist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP blacklist, The result will be discarded directly| blacklist-ip 1.2.3.4/16

+ 1 - 0
ReadMe_zh-CN.md

@@ -395,6 +395,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
 |server-tls|上游TLS DNS|无|[IP][:port] [-blacklist-ip][-check-edns],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tls 8.8.8.8:853
 |address|指定域名IP地址|无|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-`表示忽略, `#`表示返回SOA, `4`表示IPV4, `6`表示IPV6| address /www.example.com/1.2.3.4
 |ipset|域名IPSET|None|ipset /domain/[ipset\|-], `-`表示忽略|ipset /www.example.com/pass
+|ipset-timeout|设置IPSET超时功能启用|auto|[yes]|ipset-timeout yes
 |bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16
 |ignore-ip|忽略IP地址|无|[ip/subnet],可重复| ignore-ip 1.2.3.4/16
 |blacklist-ip|黑名单IP地址|无|[ip/subnet],可重复| blacklist-ip 1.2.3.4/16

+ 3 - 0
etc/smartdns/smartdns.conf

@@ -102,6 +102,9 @@ log-level info
 # address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all
 # address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all
 
+# enable ipset timeout by ttl feature
+# ipset-timeout [yes]
+
 # specific ipset to domain
 # ipset /domain/[ipset|-]
 # ipset /www.example.com/block, set ipset with ipset name of block 

+ 1 - 1
src/dns_cache.c

@@ -147,7 +147,7 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type
 	dns_cache->cname[0] = 0;
 	dns_cache->qtype = qtype;
 	dns_cache->ttl = ttl;
-	dns_cache->hitnum = 6;
+	dns_cache->hitnum = 2;
 	atomic_set(&dns_cache->ref, 1);
 	time(&dns_cache->insert_time);
 	if (qtype == DNS_T_A) {

+ 3 - 0
src/dns_conf.c

@@ -45,6 +45,8 @@ int dns_conf_rr_ttl_min;
 int dns_conf_rr_ttl_max;
 int dns_conf_force_AAAA_SOA;
 
+int dns_conf_ipset_timeout_enable;
+
 struct dns_edns_client_subnet dns_conf_ipv4_ecs;
 struct dns_edns_client_subnet dns_conf_ipv6_ecs;
 
@@ -706,6 +708,7 @@ struct config_item config_item[] = {
 	CONF_CUSTOM("server-tcp", config_server_tcp, NULL),
 	CONF_CUSTOM("server-tls", config_server_tls, NULL),
 	CONF_CUSTOM("address", config_address, NULL),
+	CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable),
 	CONF_CUSTOM("ipset", config_ipset, NULL),
 	CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
 	CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),

+ 1 - 0
src/dns_conf.h

@@ -133,6 +133,7 @@ extern int dns_conf_rr_ttl;
 extern int dns_conf_rr_ttl_min;
 extern int dns_conf_rr_ttl_max;
 extern int dns_conf_force_AAAA_SOA;
+extern int dns_conf_ipset_timeout_enable;
 
 extern struct dns_edns_client_subnet dns_conf_ipv4_ecs;
 extern struct dns_edns_client_subnet dns_conf_ipv6_ecs;

+ 20 - 8
src/dns_server.c

@@ -408,6 +408,10 @@ static int _dns_reply(struct dns_request *request)
 	int ret = 0;
 	int encode_len = 0;
 
+	if (request->client == NULL) {
+		return 0;
+	}
+
 	_dns_server_audit_log(request);
 
 	memset(&head, 0, sizeof(head));
@@ -490,14 +494,14 @@ static int _dns_setup_ipset(struct dns_request *request)
 	}
 
 	if (request->has_ipv4 && request->qtype == DNS_T_A) {
-		ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN);
+		ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
 	}
 
 	if (request->has_ipv6 && request->qtype == DNS_T_AAAA) {
 		if (request->has_ipv4) {
-			ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN);
+			ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
 		}
-		ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN);
+		ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
 	}
 
 	tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, result: %d", request->domain, ipset_rule->ipsetname, ret);
@@ -548,7 +552,12 @@ int _dns_server_request_complete(struct dns_request *request)
 
 			if ((request->ping_ttl_v4 + (dns_conf_dualstack_ip_selection_threshold * 10)) < request->ping_ttl_v6 || request->ping_ttl_v6 < 0) {
 				tlog(TLOG_DEBUG, "Force IPV4 perfered.");
-				dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN);
+				if (request->prefetch) {
+					dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN);
+				} else {
+					dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN);
+				}
+
 				return _dns_server_reply_SOA(DNS_RC_NOERROR, request, NULL);
 			}
 
@@ -575,15 +584,16 @@ int _dns_server_request_complete(struct dns_request *request)
 		}
 	}
 
-	if (request->prefetch) {
-		return 0;
-	}
-
 	if (request->has_soa) {
 		tlog(TLOG_INFO, "result: %s, qtype: %d, SOA", request->domain, request->qtype);
 	}
 
 	_dns_setup_ipset(request);
+
+	if (request->prefetch) {
+		return 0;
+	}
+
 	_dns_reply(request);
 
 	return 0;
@@ -1594,6 +1604,8 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype)
 	hash_init(request->ip_map);
 	strncpy(request->domain, domain, DNS_MAX_CNAME_LEN);
 
+	request->domain_rule = _dns_server_get_domain_rule(request->domain);
+
 	tlog(TLOG_INFO, "prefetch domain %s, qtype = %d\n", request->domain, qtype);
 
 	_dns_server_request_get(request);

+ 24 - 8
src/util.c

@@ -1,4 +1,5 @@
 #include "util.h"
+#include "dns_conf.h"
 #include <arpa/inet.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -19,6 +20,7 @@
 #define IPSET_ATTR_IPADDR_IPV6 2
 #define IPSET_ATTR_PROTOCOL 1
 #define IPSET_ATTR_SETNAME 2
+#define IPSET_ATTR_TIMEOUT 6
 #define IPSET_ADD 9
 #define IPSET_DEL 10
 #define IPSET_MAXNAMELEN 32
@@ -246,11 +248,20 @@ static int _ipset_socket_init(void)
 	return 0;
 }
 
-static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, int operate)
+static int _ipset_support_timeout(const char *ipsetname) 
+{
+	if (dns_conf_ipset_timeout_enable) {
+		return 0;
+	}
+	
+	return -1;
+}
+
+static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout, int operate)
 {
 	struct nlmsghdr *netlink_head;
 	struct ipset_netlink_msg *netlink_msg;
-	struct ipset_netlink_attr *nested[2];
+	struct ipset_netlink_attr *nested[3];
 	char buffer[BUFF_SZ];
 	uint8_t proto;
 	ssize_t rc;
@@ -285,7 +296,7 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int
 	netlink_head = (struct nlmsghdr *)buffer;
 	netlink_head->nlmsg_len = NETLINK_ALIGN(sizeof(struct nlmsghdr));
 	netlink_head->nlmsg_type = operate | (NFNL_SUBSYS_IPSET << 8);
-	netlink_head->nlmsg_flags = NLM_F_REQUEST;
+	netlink_head->nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE;
 
 	netlink_msg = (struct ipset_netlink_msg *)(buffer + netlink_head->nlmsg_len);
 	netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_msg));
@@ -303,9 +314,15 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int
 	nested[1] = (struct ipset_netlink_attr *)(buffer + NETLINK_ALIGN(netlink_head->nlmsg_len));
 	netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_attr));
 	nested[1]->type = NLA_F_NESTED | IPSET_ATTR_IP;
-	_ipset_add_attr(netlink_head, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len, addr);
 
+	_ipset_add_attr(netlink_head, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len, addr);
 	nested[1]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[1];
+
+	if (timeout > 0 && _ipset_support_timeout(ipsetname) == 0) {
+		timeout = htonl(timeout);
+		_ipset_add_attr(netlink_head, IPSET_ATTR_TIMEOUT | NLA_F_NET_BYTEORDER, sizeof(timeout), &timeout);
+	}
+
 	nested[0]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[0];
 
 	for (;;) {
@@ -326,17 +343,16 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int
 	return rc;
 }
 
-int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len)
+int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout)
 {
-	return _ipset_operate(ipsetname, addr, addr_len, IPSET_ADD);
+	return _ipset_operate(ipsetname, addr, addr_len, timeout, IPSET_ADD);
 }
 
 int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len)
 {
-	return _ipset_operate(ipsetname, addr, addr_len, IPSET_DEL);
+	return _ipset_operate(ipsetname, addr, addr_len, 0, IPSET_DEL);
 }
 
-
 #define THREAD_STACK_SIZE (16*1024)
 static pthread_mutex_t *lock_cs;
 static long *lock_count;

+ 1 - 1
src/util.h

@@ -22,7 +22,7 @@ char *reverse_string(char *output, char *input, int len);
 
 void print_stack(void);
 
-int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len);
+int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout);
 
 int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len);