Browse Source

Add Bogus ip filter

Nick Peng 7 years ago
parent
commit
55e24625c7
9 changed files with 182 additions and 14 deletions
  1. 1 0
      ReadMe.md
  2. 1 0
      ReadMe_zh-CN.md
  3. 3 0
      etc/smartdns/smartdns.conf
  4. 4 1
      package/openwrt/custom.conf
  5. 110 5
      src/conf.c
  6. 20 0
      src/conf.h
  7. 2 2
      src/dns_cache.c
  8. 3 3
      src/dns_client.c
  9. 38 3
      src/dns_server.c

+ 1 - 0
ReadMe.md

@@ -381,6 +381,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
 |server|Upstream UDP DNS server|None|[ip][:port], Repeatable| server 8.8.8.8:53
 |server-tcp|Upstream TCP DNS server|None|[IP][:port], Repeatable| server-tcp 8.8.8.8:53
 |address|Domain IP address|None|address /domain/ip| address /www.example.com/1.2.3.4
+|bogus-nxdomain|bogus IP address|None|[IP],Repeatable| bogus-nxdomain 1.2.3.4
 
 ## [Donate](#Donate)  
 

+ 1 - 0
ReadMe_zh-CN.md

@@ -381,6 +381,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
 |server|上游UDP DNS|无|[ip][:port],可重复| server 8.8.8.8:53
 |server-tcp|上游TCP DNS|无|[IP][:port],可重复| server-tcp 8.8.8.8:53
 |address|指定域名IP地址|无|address /domain/ip| address /www.example.com/1.2.3.4
+|bogus-nxdomain|假冒IP地址过滤|无|[ip],可重复| bogus-nxdomain 1.2.3.4
 
 ## [Donate](#Donate)  
 

+ 3 - 0
etc/smartdns/smartdns.conf

@@ -45,3 +45,6 @@ log-level error
 # specific address to domain
 # address /domain/ip
 # address /www.example.com/1.2.3.4
+
+# List of hosts that supply bogus NX domain results 
+# bogus-nxdomain [ip]

+ 4 - 1
package/openwrt/custom.conf

@@ -8,4 +8,7 @@
 # log-size 128k
 
 # log-file /var/log/smartdns.log
-# log-num 2
+# log-num 2
+
+# List of hosts that supply bogus NX domain results 
+# bogus-nxdomain [ip]

+ 110 - 5
src/conf.c

@@ -1,7 +1,7 @@
 #include "conf.h"
-#include "tlog.h"
 #include "list.h"
 #include "rbtree.h"
+#include "tlog.h"
 #include "util.h"
 #include <stdio.h>
 #include <stdlib.h>
@@ -16,6 +16,7 @@
 char dns_conf_server_ip[DNS_MAX_IPLEN];
 int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
 struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
+struct dns_bogus_nxdomain dns_conf_bogus_nxdomain;
 char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
 int dns_conf_server_num;
 int dns_conf_log_level = TLOG_ERROR;
@@ -119,7 +120,7 @@ int config_address(char *value)
 	memset(address, 0, sizeof(*address));
 	len = end - begin;
 	memcpy(domain + 1, begin, len);
-	
+
 	/* add dot for subdomain */
 	domain[0] = '.';
 	len++;
@@ -306,9 +307,113 @@ int config_rr_ttl_max(char *value)
 	return 0;
 }
 
+int dns_bogus_nxdomain_exists(unsigned char *ip, dns_type_t addr_type)
+{
+	uint32_t key = 0;
+	struct dns_bogus_ip_address *ip_addr = NULL;
+	int addr_len = 0;
+
+	if (addr_type == DNS_T_A) {
+		addr_len = 4;
+	} else if (addr_type == DNS_T_AAAA) {
+		addr_len = 16;
+	} else {
+		return -1;
+	}
+
+	key = jhash(ip, addr_len, 0);
+	hash_for_each_possible(dns_conf_bogus_nxdomain.ip_hash, ip_addr, node, key)
+	{
+		if (addr_type == DNS_T_A) {
+			if (memcmp(ip_addr->ipv4_addr, ip, addr_len) == 0) {
+				return 0;
+			}
+		} else if (addr_type == DNS_T_AAAA) {
+			if (memcmp(ip_addr->ipv6_addr, ip, addr_len) == 0) {
+				return 0;
+			}
+		}
+	}
+
+	return -1;
+}
+
+void conf_bogus_nxdomain_destroy(void)
+{
+	struct dns_bogus_ip_address *ip_addr = NULL;
+	struct hlist_node *tmp = NULL;
+	int i;
+
+	hash_for_each_safe(dns_conf_bogus_nxdomain.ip_hash, i, tmp, ip_addr, node)
+	{
+		hlist_del_init(&ip_addr->node);
+		free(ip_addr);
+	}
+}
+
 int conf_bogus_nxdomain(char *value)
 {
+	struct dns_bogus_ip_address *ip_addr = NULL;
+	char ip[MAX_IP_LEN];
+	int port;
+	int ret = -1;
+	struct sockaddr_storage addr;
+	socklen_t addr_len = sizeof(addr);
+	uint32_t key;
+
+	ip_addr = malloc(sizeof(*ip_addr));
+	if (ip_addr == NULL) {
+		goto errout;
+	}
+	memset(ip_addr, 0, sizeof(*ip_addr));
+
+	if (parse_ip(value, ip, &port) != 0) {
+		goto errout;
+	}
+
+	if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
+		goto errout;
+	}
+
+	switch (addr.ss_family) {
+	case AF_INET: {
+		struct sockaddr_in *addr_in;
+		addr_in = (struct sockaddr_in *)&addr;
+		memcpy(ip_addr->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
+		ip_addr->addr_type = DNS_T_A;
+		addr_len = 4;
+	} break;
+	case AF_INET6: {
+		struct sockaddr_in6 *addr_in6;
+		addr_in6 = (struct sockaddr_in6 *)&addr;
+		if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
+			memcpy(ip_addr->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
+			ip_addr->addr_type = DNS_T_A;
+			addr_len = 4;
+		} else {
+			memcpy(ip_addr->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
+			addr_len = 16;
+		}
+	} break;
+	default:
+		goto errout;
+	}
+
+	if (dns_bogus_nxdomain_exists(ip_addr->addr, ip_addr->addr_type) == 0) {
+		ret = 0;
+		goto errout;
+	}
+
+	key = jhash(ip_addr->addr, addr_len, 0);
+	hash_add(dns_conf_bogus_nxdomain.ip_hash, &ip_addr->node, key);
+
 	return 0;
+errout:
+	if (ip_addr) {
+		free(ip_addr);
+	}
+
+	return ret;
 }
 
 int config_addtional_file(char *value)
@@ -323,7 +428,6 @@ int config_addtional_file(char *value)
 	return load_conf_file(file_path);
 }
 
-
 struct config_item {
 	const char *item;
 	int (*item_func)(char *value);
@@ -344,7 +448,7 @@ struct config_item config_item[] = {
 	{"rr-ttl", config_rr_ttl},
 	{"rr-ttl-min", config_rr_ttl_min},
 	{"rr-ttl-max", config_rr_ttl_max},
-	{"bogus-nxdomain", conf_bogus_nxdomain}, 
+	{"bogus-nxdomain", conf_bogus_nxdomain},
 	{"conf-file", config_addtional_file},
 };
 int config_item_num = sizeof(config_item) / sizeof(struct config_item);
@@ -352,12 +456,13 @@ int config_item_num = sizeof(config_item) / sizeof(struct config_item);
 int load_conf_init(void)
 {
 	art_tree_init(&dns_conf_address);
-
+	hash_init(dns_conf_bogus_nxdomain.ip_hash);
 	return 0;
 }
 
 void load_exit(void)
 {
+	conf_bogus_nxdomain_destroy();
 	config_address_destroy();
 }
 

+ 20 - 0
src/conf.h

@@ -5,6 +5,8 @@
 #include "art.h"
 #include "dns.h"
 #include "dns_client.h"
+#include "hash.h"
+#include "hashtable.h"
 
 #define DNS_MAX_SERVERS 32
 #define DNS_MAX_IPLEN 64
@@ -27,11 +29,28 @@ struct dns_address {
 	};
 };
 
+/* ip address lists of domain */
+struct dns_bogus_ip_address {
+	struct hlist_node node;
+	dns_type_t addr_type;
+	union {
+		unsigned char ipv4_addr[DNS_RR_A_LEN];
+		unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
+		unsigned char addr[0];
+	};
+};
+
+struct dns_bogus_nxdomain {
+	DECLARE_HASHTABLE(ip_hash, 12);
+};
+
 extern char dns_conf_server_ip[DNS_MAX_IPLEN];
 extern int dns_conf_cachesize;
 extern struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
 extern int dns_conf_server_num;
 
+extern struct dns_bogus_nxdomain dns_conf_bogus_nxdomain;
+
 extern int dns_conf_log_level;
 extern char dns_conf_log_file[DNS_MAX_PATH];
 extern int dns_conf_log_size;
@@ -44,6 +63,7 @@ extern int dns_conf_rr_ttl;
 extern int dns_conf_rr_ttl_min;
 extern int dns_conf_rr_ttl_max;
 
+int dns_bogus_nxdomain_exists(unsigned char *ip, dns_type_t addr_type);
 
 int load_conf(const char *file);
 

+ 2 - 2
src/dns_cache.c

@@ -52,7 +52,7 @@ void dns_cache_release(struct dns_cache *dns_cache)
 
 int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr, int addr_len)
 {
-	unsigned int key = 0;
+	uint32_t key = 0;
 	struct dns_cache *dns_cache = NULL;
 
 	if (dns_cache_head.size <= 0) {
@@ -120,7 +120,7 @@ errout:
 
 struct dns_cache *dns_cache_get(char *domain, dns_type_t qtype)
 {
-	unsigned int key = 0;
+	uint32_t key = 0;
 	struct dns_cache *dns_cache = NULL;
 	struct dns_cache *dns_cache_ret = NULL;
 	time_t now;

+ 3 - 3
src/dns_client.c

@@ -492,7 +492,7 @@ static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char
 	struct dns_query_struct *query = NULL;
 	struct dns_query_struct *query_result = NULL;
 	struct hlist_node *tmp = NULL;
-	unsigned int key;
+	uint32_t key;
 
 	/* get query by hash key : id + domain */
 	key = hash_string(domain);
@@ -518,7 +518,7 @@ static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char
 
 int _dns_replied_check_add(struct dns_query_struct *dns_query, struct sockaddr *addr, socklen_t addr_len)
 {
-	int key = 0;
+	uint32_t key = 0;
 	struct dns_query_replied *replied_map = NULL;
 
 	if (addr_len > sizeof(struct sockaddr_in6)) {
@@ -1068,7 +1068,7 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
 {
 	struct dns_query_struct *query = NULL;
 	int ret = 0;
-	unsigned int key = 0;
+	uint32_t key = 0;
 
 	query = malloc(sizeof(*query));
 	if (query == NULL) {

+ 38 - 3
src/dns_server.c

@@ -441,7 +441,7 @@ int _dns_server_ping(struct dns_request *request, char *ip)
 
 int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr, dns_type_t addr_type)
 {
-	int key = 0;
+	uint32_t key = 0;
 	struct dns_ip_address *addr_map = NULL;
 	int addr_len = 0;
 
@@ -499,6 +499,22 @@ static int _dns_server_get_conf_ttl(int ttl)
 	return ttl;
 }
 
+static int _dns_server_bogus_nxdomain_exists(struct dns_request *request, unsigned char *ip, dns_type_t addr_type)
+{
+	int ret = 0;
+
+	ret = dns_bogus_nxdomain_exists(ip, addr_type);
+	if (ret != 0 ) {
+		return -1;
+	}
+
+	if (request->rcode == DNS_RC_SERVFAIL) {
+		request->rcode = DNS_RC_NXDOMAIN;
+	}
+
+	return 0;
+}
+
 static int _dns_server_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet)
 {
 	int ttl;
@@ -517,8 +533,6 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
 		return -1;
 	}
 
-	request->rcode = packet->head.rcode;
-
 	for (j = 1; j < DNS_RRS_END; j++) {
 		rrs = dns_get_rrs_start(packet, j, &rr_count);
 		for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
@@ -534,6 +548,13 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
 
 				tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
 
+				/* bogus ip address, skip */
+				if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_A) == 0) {
+					_dns_server_request_release(request);
+					tlog(TLOG_DEBUG, "bogus-nxdomain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
+					break;
+				}
+
 				if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(request->cname, name, DNS_MAX_CNAME_LEN) != 0) {
 					_dns_server_request_release(request);
 					break;
@@ -560,6 +581,8 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
 					_dns_server_request_release(request);
 					break;
 				}
+				
+				request->rcode = packet->head.rcode;
 				sprintf(ip, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
 
 				if (_dns_server_ping(request, ip) != 0) {
@@ -577,6 +600,16 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
 
 				tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", name, ttl, addr[0], addr[1],
 					 addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
+
+				/* bogus ip address, skip */
+				if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_AAAA) == 0) {
+					_dns_server_request_release(request);
+					tlog(TLOG_DEBUG, "bogus-nxdomain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", name, ttl, addr[0], addr[1],
+					 	addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
+					break;
+				}
+
+
 				if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(request->cname, name, DNS_MAX_CNAME_LEN) != 0) {
 					_dns_server_request_release(request);
 					break;
@@ -597,6 +630,8 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
 					break;
 				}
 
+				request->rcode = packet->head.rcode;
+
 				sprintf(ip, "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
 						addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);