Sfoglia il codice sorgente

Add Domain RULE flags feature.

Nick Peng 7 anni fa
parent
commit
143d82ce1a
8 ha cambiato i file con 237 aggiunte e 57 eliminazioni
  1. 2 2
      ReadMe.md
  2. 2 2
      ReadMe_zh-CN.md
  3. 7 4
      etc/smartdns/smartdns.conf
  4. 9 1
      package/openwrt/address.conf
  5. 133 43
      src/dns_conf.c
  6. 16 3
      src/dns_conf.h
  7. 66 0
      src/dns_server.c
  8. 2 2
      src/lib/art.c

+ 2 - 2
ReadMe.md

@@ -391,8 +391,8 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
 |server|Upstream UDP DNS server|None|[ip][:port] [-blacklist-ip][-check-edns], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server 8.8.8.8:53 -blacklist-ip -check-edns
 |server-tcp|Upstream TCP DNS server|None|[IP][:port] [-blacklist-ip][-check-edns], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tcp 8.8.8.8:53
 |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| address /www.example.com/1.2.3.4
-|ipset|Domain IPSet|None|ipset /domain/ipset|ipset /www.example.com/pass
+|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
 |bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 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
 |force-AAAA-SOA|force AAAA query return SOA|no|[yes\|no]|force-AAAA-SOA yes

+ 2 - 2
ReadMe_zh-CN.md

@@ -391,8 +391,8 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
 |server|上游UDP DNS|无|[ip][:port] [-blacklist-ip][-check-edns],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server 8.8.8.8:53 -blacklist-ip -check-edns
 |server-tcp|上游TCP DNS|无|[IP][:port] [-blacklist-ip][-check-edns],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tcp 8.8.8.8:53
 |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| address /www.example.com/1.2.3.4
-|ipset|域名IPSET|None|ipset /domain/ipset|ipset /www.example.com/pass
+|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
 |bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16
 |blacklist-ip|黑名单IP地址|无|[ip/subnet],可重复| blacklist-ip 1.2.3.4/16
 |force-AAAA-SOA|强制AAAA地址返回SOA|no|[yes\|no]|force-AAAA-SOA yes

+ 7 - 4
etc/smartdns/smartdns.conf

@@ -94,9 +94,12 @@ log-level info
 # server-tls 1.0.0.1
 
 # specific address to domain
-# address /domain/ip
-# address /www.example.com/1.2.3.4
+# address /domain/[ip|-|-4|-6|#|#4|#6]
+# address /www.example.com/1.2.3.4, return ip 1.2.3.4 to client
+# 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
 
 # specific ipset to domain
-# ipset /domain/ipset
-# ipset /www.example.com/block
+# ipset /domain/[ipset|-]
+# ipset /www.example.com/block, set ipset with ipset name of block 
+# ipset /www.example.com/-, ignore this domain

+ 9 - 1
package/openwrt/address.conf

@@ -1,3 +1,11 @@
 # Add domains which you want to force to an IP address here.
 # The example below send any host in example.com to a local webserver.
-# address /example.com/127.0.0.1
+# address /domain/[ip|-|-4|-6|#|#4|#6]
+# address /www.example.com/1.2.3.4, return ip 1.2.3.4 to client
+# 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
+
+# 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

+ 133 - 43
src/dns_conf.c

@@ -213,7 +213,58 @@ errout:
 		free(add_domain_rule);
 	}
 
-	tlog(TLOG_ERROR, "add doamin %s failed", domain);
+	tlog(TLOG_ERROR, "add doamin %s rule failed", domain);
+	return 0;
+}
+
+int config_domain_rule_flag_set(char *domain, unsigned int flag)
+{
+	struct dns_domain_rule *domain_rule = NULL;
+	struct dns_domain_rule *old_domain_rule = NULL;
+	struct dns_domain_rule *add_domain_rule = NULL;
+	struct dns_rule_flags *rule_flags = NULL;
+
+	char domain_key[DNS_MAX_CONF_CNAME_LEN];
+	int len = 0;
+
+	len = strlen(domain);
+	reverse_string(domain_key, domain, len);
+	domain_key[len] = '.';
+	len++;
+	domain_key[len] = 0;
+
+	domain_rule = art_search(&dns_conf_domain_rule, (unsigned char *)domain_key, len);
+	if (domain_rule == NULL) {
+		add_domain_rule = malloc(sizeof(*add_domain_rule));
+		if (add_domain_rule == NULL) {
+			goto errout;
+		}
+		memset(add_domain_rule, 0, sizeof(*add_domain_rule));
+		domain_rule = add_domain_rule;
+	}
+
+	if (domain_rule->rules[DOMAIN_RULE_FLAGS] == NULL) {
+		rule_flags = malloc(sizeof(*rule_flags));
+		rule_flags->flags = 0;
+	}
+
+	domain_rule->rules[DOMAIN_RULE_FLAGS] = rule_flags;
+	rule_flags->flags |= flag;
+
+	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);
+		}
+	}
+
+	return 0;
+errout:
+	if (add_domain_rule) {
+		free(add_domain_rule);
+	}
+
+	tlog(TLOG_ERROR, "add doamin %s rule failed", domain);
 	return 0;
 }
 
@@ -301,18 +352,26 @@ int config_ipset(void *data, int argc, char *argv[])
 		goto errout;
 	}
 
-	strncpy(ipsetname, end + 1, DNS_MAX_IPSET_NAMELEN);
-	ipset = dns_conf_get_ipset(ipsetname);
-	if (ipset == NULL) {
-		goto errout;
-	}
+	if (strncmp(end + 1, "-", sizeof("-")) != 0) {
+		strncpy(ipsetname, end + 1, DNS_MAX_IPSET_NAMELEN);
+		ipset = dns_conf_get_ipset(ipsetname);
+		if (ipset == NULL) {
+			goto errout;
+		}
 
-	ipset_rule = malloc(sizeof(*ipset_rule));
-	if (ipset_rule == NULL) {
-		goto errout;
-	}
+		ipset_rule = malloc(sizeof(*ipset_rule));
+		if (ipset_rule == NULL) {
+			goto errout;
+		}
 
-	ipset_rule->ipsetname = ipset;
+		ipset_rule->ipsetname = ipset;
+	} else {
+		if (config_domain_rule_flag_set(domain, DOMAIN_FLAG_IPSET_IGNORE) != 0 ) {
+			goto errout;
+		}
+
+		return 0;
+	}
 
 	if (config_domain_rule_add(domain, DOMAIN_RULE_IPSET, ipset_rule) != 0) {
 		goto errout;
@@ -343,6 +402,7 @@ int config_address(void *data, int argc, char *argv[])
 	struct sockaddr_storage addr;
 	socklen_t addr_len = sizeof(addr);
 	enum domain_rule type = 0;
+	unsigned int flag = 0;
 
 	if (argc <= 1) {
 		goto errout;
@@ -368,51 +428,81 @@ int config_address(void *data, int argc, char *argv[])
 	memcpy(domain, begin, len);
 	domain[len] = 0;
 
-	if (parse_ip(end + 1, ip, &port) != 0) {
-		goto errout;
-	}
+	if (strncmp(end + 1, "#", sizeof("#")) == 0) {
+		if (strncmp(end + 1, "#4", sizeof("#4")) == 0) {
+			flag = DOMAIN_FLAG_ADDR_IPV4_SOA;
+		} else if (strncmp(end + 1, "#6", sizeof("#6")) == 0) {
+			flag = DOMAIN_FLAG_ADDR_IPV6_SOA;
+		} else {
+			flag = DOMAIN_FLAG_ADDR_SOA;
+		}
 
-	if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
-		goto errout;
-	}
+		if (config_domain_rule_flag_set(domain, flag) != 0 ) {
+			goto errout;
+		}
+
+		return 0;
+	} else if (strncmp(end + 1, "-", sizeof("-")) == 0) {
+		if (strncmp(end + 1, "-4", sizeof("-4")) == 0) {
+			flag = DOMAIN_FLAG_ADDR_IPV4_IGN;
+		} else if (strncmp(end + 1, "-6", sizeof("-6")) == 0) {
+			flag = DOMAIN_FLAG_ADDR_IPV6_IGN;
+		} else {
+			flag = DOMAIN_FLAG_ADDR_IGN;
+		}
+
+		if (config_domain_rule_flag_set(domain, flag) != 0 ) {
+			goto errout;
+		}
+
+		return 0;
+	} else {
+		if (parse_ip(end + 1, ip, &port) != 0) {
+			goto errout;
+		}
 
-	switch (addr.ss_family) {
-	case AF_INET: {
-		struct sockaddr_in *addr_in;
-		address_ipv4 = malloc(sizeof(*address_ipv4));
-		if (address_ipv4 == NULL) {
+		if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
 			goto errout;
 		}
 
-		addr_in = (struct sockaddr_in *)&addr;
-		memcpy(address_ipv4->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
-		type = DOMAIN_RULE_ADDRESS_IPV4;
-		address = address_ipv4;
-	} break;
-	case AF_INET6: {
-		struct sockaddr_in6 *addr_in6;
-		addr_in6 = (struct sockaddr_in6 *)&addr;
-		if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
+		switch (addr.ss_family) {
+		case AF_INET: {
+			struct sockaddr_in *addr_in;
 			address_ipv4 = malloc(sizeof(*address_ipv4));
 			if (address_ipv4 == NULL) {
 				goto errout;
 			}
-			memcpy(address_ipv4->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
+
+			addr_in = (struct sockaddr_in *)&addr;
+			memcpy(address_ipv4->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
 			type = DOMAIN_RULE_ADDRESS_IPV4;
 			address = address_ipv4;
-		} else {
-			address_ipv6 = malloc(sizeof(*address_ipv6));
-			if (address_ipv6 == NULL) {
-				goto errout;
+		} break;
+		case AF_INET6: {
+			struct sockaddr_in6 *addr_in6;
+			addr_in6 = (struct sockaddr_in6 *)&addr;
+			if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
+				address_ipv4 = malloc(sizeof(*address_ipv4));
+				if (address_ipv4 == NULL) {
+					goto errout;
+				}
+				memcpy(address_ipv4->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
+				type = DOMAIN_RULE_ADDRESS_IPV4;
+				address = address_ipv4;
+			} else {
+				address_ipv6 = malloc(sizeof(*address_ipv6));
+				if (address_ipv6 == NULL) {
+					goto errout;
+				}
+				memcpy(address_ipv6->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
+				type = DOMAIN_RULE_ADDRESS_IPV6;
+				address = address_ipv6;
 			}
-			memcpy(address_ipv6->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
-			type = DOMAIN_RULE_ADDRESS_IPV6;
-			address = address_ipv6;
+		} break;
+		default:
+			goto errout;
 		}
-	} break;
-	default:
-		goto errout;
-	}
+	} 
 
 	if (config_domain_rule_add(domain, type, address) != 0) {
 		goto errout;

+ 16 - 3
src/dns_conf.h

@@ -22,12 +22,25 @@
 #define SMARTDNS_AUDIT_FILE "/var/log/smartdns-audit.log"
 
 enum domain_rule {
-	DOMAIN_RULE_ADDRESS_IPV4 = 1,
-	DOMAIN_RULE_ADDRESS_IPV6 = 2,
-	DOMAIN_RULE_IPSET = 3,
+	DOMAIN_RULE_FLAGS = 0,
+	DOMAIN_RULE_ADDRESS_IPV4,
+	DOMAIN_RULE_ADDRESS_IPV6,
+	DOMAIN_RULE_IPSET,
 	DOMAIN_RULE_MAX,
 };
 
+#define DOMAIN_FLAG_ADDR_SOA      (1 << 0)
+#define DOMAIN_FLAG_ADDR_IPV4_SOA (1 << 1)
+#define DOMAIN_FLAG_ADDR_IPV6_SOA (1 << 2)
+#define DOMAIN_FLAG_ADDR_IGN      (1 << 3)
+#define DOMAIN_FLAG_ADDR_IPV4_IGN (1 << 4)
+#define DOMAIN_FLAG_ADDR_IPV6_IGN (1 << 5)
+#define DOMAIN_FLAG_IPSET_IGNORE  (1 << 6)
+
+struct dns_rule_flags {
+	unsigned int flags;
+};
+
 struct dns_address_IPV4 {
 	unsigned char ipv4_addr[DNS_RR_A_LEN];
 };

+ 66 - 0
src/dns_server.c

@@ -464,12 +464,20 @@ static int _dns_server_reply_SOA(int rcode, struct dns_request *request, struct
 static int _dns_setup_ipset(struct dns_request *request)
 {
 	struct dns_ipset_rule *ipset_rule = NULL;
+	struct dns_rule_flags *rule_flags = NULL;
 	int ret = 0;
 
 	if (request->domain_rule == NULL) {
 		return 0;
 	}
 
+	rule_flags = request->domain_rule->rules[DOMAIN_RULE_FLAGS];
+	if (rule_flags) {
+		if (rule_flags->flags & DOMAIN_FLAG_IPSET_IGNORE) {
+			return 0;
+		}
+	}
+
 	ipset_rule = request->domain_rule->rules[DOMAIN_RULE_IPSET];
 	if (ipset_rule == NULL) {
 		return 0;
@@ -1196,6 +1204,59 @@ static struct dns_domain_rule *_dns_server_get_domain_rule(char *domain)
 	return domain_rule;
 }
 
+static int _dns_server_pre_process_rule_flags(struct dns_request *request, struct dns_packet *packet)
+{
+	struct dns_rule_flags *rule_flag = NULL;
+	unsigned int flags = 0;
+	if (request->domain_rule == NULL) {
+		goto errout;
+	}
+
+	rule_flag = request->domain_rule->rules[DOMAIN_RULE_FLAGS];
+	if (rule_flag == NULL) {
+		goto errout;
+	}
+
+	flags = rule_flag->flags;
+	if (flags & DOMAIN_FLAG_ADDR_IGN) {
+		goto errout;
+	}
+
+	if (flags & DOMAIN_FLAG_ADDR_SOA) {
+		_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
+		return 0;
+	}
+
+	switch (request->qtype) {
+	case DNS_T_A:
+		if (flags & DOMAIN_FLAG_ADDR_IPV4_IGN) {
+			goto errout;
+		}
+
+		if (flags & DOMAIN_FLAG_ADDR_IPV4_SOA) {
+			_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
+			return 0;
+		}
+		break;
+	case DNS_T_AAAA:
+		if (flags & DOMAIN_FLAG_ADDR_IPV6_IGN) {
+			goto errout;
+		}
+
+		if (flags & DOMAIN_FLAG_ADDR_IPV6_SOA) {
+			_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
+			return 0;
+		}
+		break;
+	default:
+		goto errout;
+		break;
+	}
+
+errout:
+	return -1;
+}
+
 static int _dns_server_process_address(struct dns_request *request, struct dns_packet *packet)
 {
 	struct dns_address_IPV4 *address_ipv4 = NULL;
@@ -1369,6 +1430,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
 			_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
 			goto clean_exit;
 		}
+		
 		break;
 	default:
 		tlog(TLOG_DEBUG, "unsupport qtype: %d, domain: %s", qtype, request->domain);
@@ -1376,6 +1438,10 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
 		break;
 	}
 
+	if (_dns_server_pre_process_rule_flags(request, packet) == 0) {
+		goto clean_exit;
+	}
+
 	if (_dns_server_process_address(request, packet) == 0) {
 		goto clean_exit;
 	}

+ 2 - 2
src/lib/art.c

@@ -1027,7 +1027,6 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len, un
             // Check if the expanded path matches
             if (!str_prefix_matches((art_leaf*)n, str, str_len)) {
                 found = (art_leaf*)n;
-				art_copy_key(found, key, key_len);
 			}
             break;
         }
@@ -1040,7 +1039,6 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len, un
             // Check if the expanded path matches
             if (!str_prefix_matches((art_leaf*)m, str, str_len)) {
                 found = (art_leaf*)m;
-                art_copy_key(found, key, key_len);
             }
     	}
 
@@ -1062,5 +1060,7 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len, un
         return NULL;
     }
 
+    art_copy_key(found, key, key_len);
+
     return found->value;
 }