From 55e24625c721b66f37ef2b5c0387eb22b44aadd0 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Fri, 17 Aug 2018 00:02:19 +0800 Subject: [PATCH] Add Bogus ip filter --- ReadMe.md | 1 + ReadMe_zh-CN.md | 1 + etc/smartdns/smartdns.conf | 3 + package/openwrt/custom.conf | 5 +- src/conf.c | 115 ++++++++++++++++++++++++++++++++++-- src/conf.h | 20 +++++++ src/dns_cache.c | 4 +- src/dns_client.c | 6 +- src/dns_server.c | 41 ++++++++++++- 9 files changed, 182 insertions(+), 14 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 69ede6d..65c419d 100755 --- a/ReadMe.md +++ b/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) diff --git a/ReadMe_zh-CN.md b/ReadMe_zh-CN.md index eddf523..e6333dd 100644 --- a/ReadMe_zh-CN.md +++ b/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) diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index 0993612..33e3262 100644 --- a/etc/smartdns/smartdns.conf +++ b/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] diff --git a/package/openwrt/custom.conf b/package/openwrt/custom.conf index fd552bc..54aee7c 100644 --- a/package/openwrt/custom.conf +++ b/package/openwrt/custom.conf @@ -8,4 +8,7 @@ # log-size 128k # log-file /var/log/smartdns.log -# log-num 2 \ No newline at end of file +# log-num 2 + +# List of hosts that supply bogus NX domain results +# bogus-nxdomain [ip] \ No newline at end of file diff --git a/src/conf.c b/src/conf.c index f6dfddb..06309ae 100644 --- a/src/conf.c +++ b/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 #include @@ -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(); } diff --git a/src/conf.h b/src/conf.h index 34a1477..615bdfa 100644 --- a/src/conf.h +++ b/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); diff --git a/src/dns_cache.c b/src/dns_cache.c index d78ecc6..b09dcc2 100644 --- a/src/dns_cache.c +++ b/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; diff --git a/src/dns_client.c b/src/dns_client.c index d85cd19..db81b2b 100644 --- a/src/dns_client.c +++ b/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) { diff --git a/src/dns_server.c b/src/dns_server.c index 54f45fd..bd72127 100644 --- a/src/dns_server.c +++ b/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]);