瀏覽代碼

Optimize configuration, and add blacklist ip features

Nick Peng 7 年之前
父節點
當前提交
62f331c153

+ 5 - 4
ReadMe.md

@@ -388,11 +388,12 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
 |audit-size|audit log size|128K|number+K,M,G|audit-size 128K
 |audit-num|archived audit log number|2|Integer|audit-num 2
 |conf-file|additional conf file|None|File path|conf-file /etc/smartdns/smartdns.more.conf
-|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
-|server-tls|Upstream TLS DNS server|None|[IP][:port], Repeatable| server-tls 8.8.8.8:853
+|server|Upstream UDP DNS server|None|[ip][:port] [-blacklist-ip], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server 8.8.8.8:53
+|server-tcp|Upstream TCP DNS server|None|[IP][:port] [-blacklist-ip], 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], 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
-|bogus-nxdomain|bogus IP address|None|[IP],Repeatable| bogus-nxdomain 1.2.3.4
+|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
 
 ## [Donate](#Donate)  

+ 5 - 4
ReadMe_zh-CN.md

@@ -388,11 +388,12 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
 |audit-size|审计大小|128K|数字+K,M,G|audit-size 128K
 |audit-num|审计归档个数|2|数字|audit-num 2
 |conf-file|附加配置文件|无|文件路径|conf-file /etc/smartdns/smartdns.more.conf
-|server|上游UDP DNS|无|[ip][:port],可重复| server 8.8.8.8:53
-|server-tcp|上游TCP DNS|无|[IP][:port],可重复| server-tcp 8.8.8.8:53
-|server-tls|上游TLS DNS|无|[IP][:port],可重复| server-tls 8.8.8.8:853
+|server|上游UDP DNS|无|[ip][:port] [-blacklist-ip],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server 8.8.8.8:53 -blacklist-ip
+|server-tcp|上游TCP DNS|无|[IP][:port] [-blacklist-ip],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tcp 8.8.8.8:53
+|server-tls|上游TLS DNS|无|[IP][:port] [-blacklist-ip],可重复,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
-|bogus-nxdomain|假冒IP地址过滤|无|[ip],可重复| bogus-nxdomain 1.2.3.4
+|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
 
 ## [Donate](#Donate)  

+ 18 - 8
etc/smartdns/smartdns.conf

@@ -4,6 +4,10 @@
 #   server-name smartdns
 #
 
+# Include another configuration options
+# conf-file [file]
+# conf-file blacklist-ip.conf
+
 # dns server bind ip and port, default dns server port is 53.
 # bind [IP]:port, udp server
 # bind-tcp [IP]:port, tcp server
@@ -27,7 +31,10 @@ cache-size 512
 # prefetch-domain yes
 
 # List of hosts that supply bogus NX domain results 
-# bogus-nxdomain [ip]
+# bogus-nxdomain [ip/subnet]
+
+# List of IPs that will be filtered when nameserver is configured -blacklist-ip parameter
+# blacklist-ip [ip/subnet]
 
 # force AAAA query return SO
 # force-AAAA-SOA [yes|no]
@@ -46,7 +53,7 @@ cache-size 512
 # log-file: file path of log file.
 # log-size: size of each log file, support k,m,g
 # log-num: number of logs
-log-level error
+log-level info
 # log-file /var/log/smartdns.log
 # log-size 128k
 # log-num 2
@@ -59,17 +66,20 @@ log-level error
 # audit-num 2
 
 # remote udp dns server list
-# server [IP]:[PORT], default port is 53
-# server 8.8.8.8
+# server [IP]:[PORT] [-blacklist-ip]
+# default port is 53
+# server 8.8.8.8 -blacklist-ip
 
 # remote tcp dns server list
-# server-tcp [IP]:[PORT], default port is 53
+# server-tcp [IP]:[PORT] [-blacklist-ip]
+# default port is 53
 # server-tcp 8.8.8.8
 
 # remote tls dns server list
-# server-tls [IP]:[PORT], default port is 853
-#server-tls 8.8.8.8
-#server-tls 1.0.0.1
+# server-tls [IP]:[PORT] [-blacklist-ip]
+# default port is 853
+# server-tls 8.8.8.8
+# server-tls 1.0.0.1
 
 # specific address to domain
 # address /domain/ip

+ 15 - 0
package/luci/files/luci/i18n/smartdns.zh-cn.po

@@ -121,12 +121,27 @@ msgstr "协议类型"
 msgid "Domain Address"
 msgstr "域名地址"
 
+msgid "IP Blacklist Filtering"
+msgstr "IP黑名单过滤"
+
+msgid "Filtering IP with blacklist"
+msgstr "使用IP黑名单过滤"
+
 msgid "Set Specific domain ip address."
 msgstr "指定特定域名的IP地址"
 
 msgid "Specify an IP address to return for any host in the given domains, Queries in the domains are never forwarded and always replied to with the specified IP address which may be IPv4 or IPv6."
 msgstr "配置特定域名返回特定的IP地址,域名查询将不到上游服务器请求,直接返回配置的IP地址,可用于广告屏蔽。"
 
+msgid "IP Blacklist"
+msgstr "IP黑名单"
+
+msgid "Set Specific ip blacklist."
+msgstr "设置IP黑名单列表"
+
+msgid "Configure IP blacklists that will be filtered from the results of specific DNS server."
+msgstr "配置需要从指定域名服务器结果过滤的IP黑名单。"
+
 msgid "Technical Support"
 msgstr "技术支持"
 

+ 32 - 2
package/luci/files/luci/model/cbi/smartdns.lua

@@ -124,6 +124,14 @@ o:value("tls", translate("tls"))
 o.default     = "udp"
 o.rempty      = false
 
+---- blacklist_ip
+o = s:option(Flag, "blacklist_ip", translate("IP Blacklist Filtering"), translate("Filtering IP with blacklist"))
+o.rmempty     = false
+o.default     = o.disabled
+o.cfgvalue    = function(...)
+    return Flag.cfgvalue(...) or "0"
+end
+
 -- Doman addresss
 s = m:section(TypedSection, "smartdns", translate("Domain Address"), 
 	translate("Set Specific domain ip address."))
@@ -138,12 +146,34 @@ addr.template = "cbi/tvalue"
 addr.rows = 20
 
 function addr.cfgvalue(self, section)
-	return nixio.fs.readfile("/etc/smartdns/address.conf")
+	return nixio.fs.readfile("/var/etc/smartdns/address.conf")
+end
+
+function addr.write(self, section, value)
+	value = value:gsub("\r\n?", "\n")
+	nixio.fs.writefile("/var/etc/smartdns/address.conf", value)
+end
+
+-- IP Blacklist
+s = m:section(TypedSection, "smartdns", translate("IP Blacklist"), 
+	translate("Set Specific ip blacklist."))
+s.anonymous = true
+
+---- blacklist
+addr = s:option(Value, "blacklist_ip",
+	translate(""), 
+	translate("Configure IP blacklists that will be filtered from the results of specific DNS server."))
+
+addr.template = "cbi/tvalue"
+addr.rows = 20
+
+function addr.cfgvalue(self, section)
+	return nixio.fs.readfile("/var/etc/smartdns/blacklist-ip.conf")
 end
 
 function addr.write(self, section, value)
 	value = value:gsub("\r\n?", "\n")
-	nixio.fs.writefile("/etc/smartdns/address.conf", value)
+	nixio.fs.writefile("/var/etc/smartdns/blacklist-ip.conf", value)
 end
 
 -- Doman addresss

+ 1 - 1
package/openwrt/address.conf

@@ -1,3 +1,3 @@
 # 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 /example.com/127.0.0.1

+ 4 - 0
package/openwrt/blacklist-ip.conf

@@ -0,0 +1,4 @@
+# Add IP blacklist which you want to filtering from some DNS server here.
+# The example below filtering ip from the result of DNS server which is configured with -blacklist-ip.
+# blacklist-ip [ip/subnet]
+# blacklist-ip 254.0.0.1/16

+ 1 - 0
package/openwrt/control/conffiles

@@ -1,3 +1,4 @@
 /etc/config/smartdns
 /etc/smartdns/address.conf
+/etc/smartdns/blacklist-ip.conf
 /etc/smartdns/custom.conf

+ 15 - 1
package/openwrt/control/postinst

@@ -2,11 +2,25 @@
 
 chmod +x /usr/sbin/smartdns
 chmod +x /etc/init.d/smartdns
+mkdir -p /var/etc/smartdns/
 
 [ "${IPKG_NO_SCRIPT}" = "1" ] && exit 0
+
+if [ ! -f "/var/etc/smartdns/address.conf" ]; then
+    cp /etc/smartdns/address.conf /var/etc/smartdns/address.conf
+fi
+
+if [ ! -f "/var/etc/smartdns/blacklist-ip.conf" ]; then
+    cp /etc/smartdns/blacklist-ip.conf /var/etc/smartdns/blacklist-ip.conf
+fi
+
+if [ ! -f "/var/etc/smartdns/custom.conf" ]; then
+    cp /etc/smartdns/custom.conf /var/etc/smartdns/custom.conf
+fi
+
 . ${IPKG_INSTROOT}/lib/functions.sh
 default_postinst $0 $@
 ret=$?
 /etc/init.d/smartdns enable
-exit $ret
+exit 0
 

+ 3 - 0
package/openwrt/control/prerm

@@ -1,3 +1,6 @@
 #!/bin/sh
 . ${IPKG_INSTROOT}/lib/functions.sh
 default_prerm $0 $@
+rm /var/etc/smartdns.conf -f
+rm /var/etc/smartdns/smartdns.conf -f
+exit 0

+ 1 - 1
package/openwrt/custom.conf

@@ -11,4 +11,4 @@
 # log-num 2
 
 # List of hosts that supply bogus NX domain results 
-# bogus-nxdomain [ip]
+# bogus-nxdomain [ip/subnet]

+ 18 - 5
package/openwrt/files/etc/init.d/smartdns

@@ -8,10 +8,13 @@ SERVICE_WRITE_PID=1
 SERVICE_DAEMONIZE=1
 SERVICE_PID_FILE="/var/run/smartdns.pid"
 BASECONFIGFILE="/etc/smartdns/smartdns.conf"
-SMARTDNS_CONF="/var/etc/smartdns.conf"
-ADDRESS_CONF="/etc/smartdns/address.conf"
-CUSTOM_CONF="/etc/smartdns/custom.conf"
+SMARTDNS_CONF_DIR="/var/etc/smartdns"
+SMARTDNS_CONF="$SMARTDNS_CONF_DIR/smartdns.conf"
+ADDRESS_CONF="$SMARTDNS_CONF_DIR/address.conf"
+BLACKLIST_IP_CONF="$SMARTDNS_CONF_DIR/blacklist-ip.conf"
+CUSTOM_CONF="$SMARTDNS_CONF_DIR/custom.conf"
 SMARTDNS_CONF_TMP="${SMARTDNS_CONF}.tmp"
+COREDUMP="0"
 
 set_forward_dnsmasq()
 {
@@ -109,9 +112,11 @@ conf_append()
 load_server()
 {
 	local section="$1"
+	local ADDITIONAL_ARGS=""
 	config_get "port" "$section" "port" "53"
 	config_get "type" "$section" "type" "udp"
 	config_get "ip" "$section" "ip" ""
+	config_get "blacklist_ip" "$section" "blacklist_ip" "0"
 
 	if [ -z "$port" ] || [ -z "$ip" ] || [ -z "$type" ]; then
 		return
@@ -130,8 +135,11 @@ load_server()
 		fi
 	fi
 
-	conf_append "$SERVER" "$ip:$port"
+	if [ "$blacklist_ip" != "0" ]; then
+		ADDITIONAL_ARGS="$ADDITIONAL_ARGS -blacklist-ip"
+	fi
 
+	conf_append "$SERVER" "$ip:$port $ADDITIONAL_ARGS"
 }
 
 start_service() {
@@ -161,7 +169,7 @@ start_service() {
 	fi
 	SMARTDNS_PORT="$port"
 
-	mkdir -p $(dirname $SMARTDNS_CONF)
+	mkdir -p $SMARTDNS_CONF_DIR
 
 	config_get "cache_size" "$section" "cache_size" ""
 	if [ ! -z "$cache_size" ]; then
@@ -227,11 +235,16 @@ start_service() {
 	config_foreach load_server "server"
 
 	echo "conf-file $ADDRESS_CONF" >> $SMARTDNS_CONF_TMP
+	echo "conf-file $BLACKLIST_IP_CONF" >> $SMARTDNS_CONF_TMP
 	echo "conf-file $CUSTOM_CONF" >> $SMARTDNS_CONF_TMP
 
 	config_get_bool "enabled" "$section" "enabled" '0'
 	mv $SMARTDNS_CONF_TMP $SMARTDNS_CONF
 	[ "$enabled" -gt 0 ] || return 1
+	if [ "$COREDUMP" = "1" ]; then
+		args="$args -S"
+		ulimit -c unlimited
+	fi
 	service_start /usr/sbin/smartdns $args -c $SMARTDNS_CONF
 }
 

+ 2 - 0
package/openwrt/make.sh

@@ -7,6 +7,7 @@ SMARTDNS_DIR=$CURR_DIR/../../
 SMARTDNS_BIN=$SMARTDNS_DIR/src/smartdns
 SMARTDNS_CONF=$SMARTDNS_DIR/etc/smartdns/smartdns.conf
 ADDRESS_CONF=$CURR_DIR/address.conf
+BLACKLIST_IP_CONF=$CURR_DIR/blacklist-ip.conf
 CUSTOM_CONF=$CURR_DIR/custom.conf
 
 showhelp()
@@ -33,6 +34,7 @@ build()
 
     cp $SMARTDNS_CONF  $ROOT/root/etc/smartdns/
     cp $ADDRESS_CONF $ROOT/root/etc/smartdns/
+    cp $BLACKLIST_IP_CONF $ROOT/root/etc/smartdns/
     cp $CUSTOM_CONF $ROOT/root/etc/smartdns/
     cp $CURR_DIR/files/etc $ROOT/root/ -af
     cp $SMARTDNS_BIN $ROOT/root/usr/sbin

+ 2 - 2
src/Makefile

@@ -1,7 +1,7 @@
 
 BIN=smartdns 
-OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o
-OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o conf.o dns_cache.o $(OBJS_LIB)
+OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o
+OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o $(OBJS_LIB)
 CFLAGS +=-O2 -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing 
 CFLAGS +=-Iinclude
 CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"

+ 0 - 738
src/conf.c

@@ -1,738 +0,0 @@
-#include "conf.h"
-#include "list.h"
-#include "rbtree.h"
-#include "tlog.h"
-#include "util.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define MAX_LINE_LEN 1024
-#define MAX_KEY_LEN 64
-
-#define DEFAULT_DNS_CACHE_SIZE 512
-
-char dns_conf_server_ip[DNS_MAX_IPLEN];
-char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
-int dns_conf_tcp_idle_time = 120;
-int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
-int dns_conf_prefetch = 0;
-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;
-char dns_conf_log_file[DNS_MAX_PATH];
-int dns_conf_log_size = 1024 * 1024;
-int dns_conf_log_num = 8;
-int dns_conf_audit_enable = 0;
-char dns_conf_audit_file[DNS_MAX_PATH];
-int dns_conf_audit_size = 1024 * 1024;
-int dns_conf_audit_num = 2;
-
-art_tree dns_conf_domain_rule;
-radix_tree_t *dns_conf_address_rule;
-
-int dns_conf_rr_ttl;
-int dns_conf_rr_ttl_min;
-int dns_conf_rr_ttl_max;
-int dns_conf_force_AAAA_SOA;
-
-int load_conf_file(const char *file);
-
-int config_bind(char *value)
-{
-	/* server bind address */
-	strncpy(dns_conf_server_ip, value, DNS_MAX_IPLEN);
-
-	return 0;
-}
-
-int config_bind_tcp(char *value)
-{
-	/* server bind address */
-	strncpy(dns_conf_server_tcp_ip, value, DNS_MAX_IPLEN);
-
-	return 0;
-}
-
-int config_server_name(char *value)
-{
-	strncpy(dns_conf_server_name, value, DNS_MAX_CONF_CNAME_LEN);
-	return 0;
-}
-
-int config_server(char *value, dns_server_type_t type, int default_port)
-{
-	int index = dns_conf_server_num;
-	struct dns_servers *server;
-	int port = -1;
-
-	if (index >= DNS_MAX_SERVERS) {
-		tlog(TLOG_ERROR, "exceeds max server number");
-		return -1;
-	}
-
-	server = &dns_conf_servers[index];
-	/* parse ip, port from value */
-	if (parse_ip(value, server->server, &port) != 0) {
-		return -1;
-	}
-
-	/* if port is not defined, set port to default 53 */
-	if (port == PORT_NOT_DEFINED) {
-		port = default_port;
-	}
-
-	server->type = type;
-	server->port = port;
-	dns_conf_server_num++;
-
-	return 0;
-}
-
-int config_domain_iter_cb(void *data, const unsigned char *key, uint32_t key_len, void *value)
-{
-	free(value);
-	return 0;
-}
-
-void config_domain_destroy(void)
-{
-	art_iter(&dns_conf_domain_rule, config_domain_iter_cb, 0);
-	art_tree_destroy(&dns_conf_domain_rule);
-}
-
-void config_address_destroy(radix_node_t *node, void *cbctx)
-{
-	if (node == NULL) {
-		return;
-	}
-
-	if (node->data == NULL) {
-		return;
-	}
-
-	free(node->data);
-	node->data = NULL;
-}
-
-int config_address(char *value)
-{
-	struct dns_address *address = NULL;
-	struct dns_address *oldaddress;
-	char ip[MAX_IP_LEN];
-	char domain_key[DNS_MAX_CONF_CNAME_LEN];
-	char domain[DNS_MAX_CONF_CNAME_LEN];
-	char *begin = NULL;
-	char *end = NULL;
-	int len = 0;
-	int port;
-	struct sockaddr_storage addr;
-	socklen_t addr_len = sizeof(addr);
-	char type = '4';
-
-	begin = strstr(value, "/");
-	if (begin == NULL) {
-		goto errout;
-	}
-
-	begin++;
-	end = strstr(begin, "/");
-	if (end == NULL) {
-		goto errout;
-	}
-
-	address = malloc(sizeof(*address));
-	if (address == NULL) {
-		goto errout;
-	}
-	
-	/* remove prefix . */
-	while (*begin == '.') {
-		begin++;
-	}
-
-	memset(address, 0, sizeof(*address));
-	len = end - begin;
-	memcpy(domain + 1, begin, len);
-
-	/* add dot for subdomain */
-	domain[0] = '.';
-	len++;
-
-	domain[len] = 0;
-	reverse_string(domain_key + 1, domain, len);
-
-	if (parse_ip(end + 1, 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(address->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
-		address->addr_type = DNS_T_A;
-		type = '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(address->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
-			address->addr_type = DNS_T_A;
-			type = '4';
-		} else {
-			memcpy(address->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
-			address->addr_type = DNS_T_AAAA;
-			type = '6';
-		}
-	} break;
-	default:
-		goto errout;
-	}
-
-	domain_key[0] = type;
-	len++;
-	oldaddress = art_insert(&dns_conf_domain_rule, (unsigned char *)domain_key, len, address);
-	if (oldaddress) {
-		free(oldaddress);
-	}
-
-	return 0;
-errout:
-	if (address) {
-		free(address);
-	}
-
-	tlog(TLOG_ERROR, "add address %s failed", value);
-	return 0;
-}
-
-int config_server_udp(char *value)
-{
-	return config_server(value, DNS_SERVER_UDP, DEFAULT_DNS_PORT);
-}
-
-int config_server_tcp(char *value)
-{
-	return config_server(value, DNS_SERVER_TCP, DEFAULT_DNS_PORT);
-}
-
-int config_tcp_idle_time(char *value)
-{
-	/* read dns cache size */
-	int idle_time = atoi(value);
-	if (idle_time < 0) {
-		return -1;
-	}
-
-	dns_conf_tcp_idle_time = idle_time;
-
-	return 0;
-}
-
-int config_server_tls(char *value)
-{
-	return config_server(value, DNS_SERVER_TLS, DEFAULT_DNS_TLS_PORT);
-}
-
-int config_cache_size(char *value)
-{
-	/* read dns cache size */
-	int cache_size = atoi(value);
-	if (cache_size < 0) {
-		return -1;
-	}
-
-	dns_conf_cachesize = cache_size;
-
-	return 0;
-}
-
-int config_cache_prefetch_domain(char *value)
-{
-	/* read dns cache size */
-	if (strncmp("yes", value, sizeof("yes")) == 0 || strncmp("YES", value, sizeof("YES")) == 0) {
-		dns_conf_prefetch = 1;
-	} else if (strncmp("no", value, sizeof("no")) == 0 || strncmp("NO", value, sizeof("NO")) == 0) {
-		dns_conf_prefetch = 0;
-	}
-
-	return 0;
-}
-
-int config_force_AAAA_SOA(char *value)
-{
-	/* read dns cache size */
-	if (strncmp("yes", value, sizeof("yes")) == 0 || strncmp("YES", value, sizeof("YES")) == 0) {
-		dns_conf_force_AAAA_SOA = 1;
-	} else if (strncmp("no", value, sizeof("no")) == 0 || strncmp("NO", value, sizeof("NO")) == 0) {
-		dns_conf_force_AAAA_SOA = 0;
-	}
-
-	return 0;
-}
-
-int config_log_level(char *value)
-{
-	/* read log level and set */
-	if (strncmp("debug", value, MAX_LINE_LEN) == 0) {
-		dns_conf_log_level = TLOG_DEBUG;
-	} else if (strncmp("info", value, MAX_LINE_LEN) == 0) {
-		dns_conf_log_level = TLOG_INFO;
-	} else if (strncmp("warn", value, MAX_LINE_LEN) == 0) {
-		dns_conf_log_level = TLOG_WARN;
-	} else if (strncmp("error", value, MAX_LINE_LEN) == 0) {
-		dns_conf_log_level = TLOG_ERROR;
-	} else {
-		return -1;
-	}
-
-	return 0;
-}
-
-int config_log_file(char *value)
-{
-	/* read dns cache size */
-	strncpy(dns_conf_log_file, value, DNS_MAX_PATH);
-
-	return 0;
-}
-
-int config_log_size(char *value)
-{
-	/* read dns cache size */
-	int base = 1;
-
-	if (strstr(value, "k") || strstr(value, "K")) {
-		base = 1024;
-	} else if (strstr(value, "m") || strstr(value, "M")) {
-		base = 1024 * 1024;
-	} else if (strstr(value, "g") || strstr(value, "G")) {
-		base = 1024 * 1024 * 1024;
-	}
-
-	int size = atoi(value);
-	if (size < 0) {
-		return -1;
-	}
-
-	dns_conf_log_size = size * base;
-
-	return 0;
-}
-
-int config_log_num(char *value)
-{
-	/* read dns cache size */
-	int num = atoi(value);
-	if (num < 0) {
-		return -1;
-	}
-
-	dns_conf_log_num = num;
-
-	return 0;
-}
-
-int config_audit_enable(char *value)
-{
-	/* read dns cache size */
-	if (strncmp("yes", value, sizeof("yes")) == 0 || strncmp("YES", value, sizeof("YES")) == 0) {
-		dns_conf_audit_enable = 1;
-	} else if (strncmp("no", value, sizeof("no")) == 0 || strncmp("NO", value, sizeof("NO")) == 0) {
-		dns_conf_audit_enable = 0;
-	}
-
-	return 0;
-}
-
-int config_audit_file(char *value)
-{
-	/* read dns cache size */
-	strncpy(dns_conf_audit_file, value, DNS_MAX_PATH);
-
-	return 0;
-}
-
-int config_audit_size(char *value)
-{
-	/* read dns cache size */
-	int base = 1;
-
-	if (strstr(value, "k") || strstr(value, "K")) {
-		base = 1024;
-	} else if (strstr(value, "m") || strstr(value, "M")) {
-		base = 1024 * 1024;
-	} else if (strstr(value, "g") || strstr(value, "G")) {
-		base = 1024 * 1024 * 1024;
-	}
-
-	int size = atoi(value);
-	if (size < 0) {
-		return -1;
-	}
-
-	dns_conf_audit_size = size * base;
-
-	return 0;
-}
-
-int config_audit_num(char *value)
-{
-	/* read dns cache size */
-	int num = atoi(value);
-	if (num < 0) {
-		return -1;
-	}
-
-	dns_conf_audit_num = num;
-
-	return 0;
-}
-
-int config_rr_ttl(char *value)
-{
-	/* read dns cache size */
-	int ttl = atoi(value);
-	if (ttl < 0) {
-		return -1;
-	}
-
-	dns_conf_rr_ttl = ttl;
-
-	return 0;
-}
-
-int config_rr_ttl_min(char *value)
-{
-	/* read dns cache size */
-	int ttl = atoi(value);
-	if (ttl < 0) {
-		return -1;
-	}
-
-	dns_conf_rr_ttl_min = ttl;
-
-	return 0;
-}
-
-int config_rr_ttl_max(char *value)
-{
-	/* read dns cache size */
-	int ttl = atoi(value);
-	if (ttl < 0) {
-		return -1;
-	}
-
-	dns_conf_rr_ttl_max = ttl;
-
-	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);
-	}
-}
-
-radix_node_t *create_addr_node(radix_tree_t *tree, char *addr)
-{
-	radix_node_t *node;
-	void         *p;
-	prefix_t     prefix;
-	const char *errmsg = NULL;
-
-	p = prefix_pton(addr, -1, &prefix, &errmsg);
-	if (p == NULL) {
-		return NULL;
-	}
-
-	node = radix_lookup(tree, &prefix);
-	return node;
-}
-
-
-int config_iplist_action(char *subnet, enum address_action act)
-{
-	radix_node_t *node = NULL;
-	struct dns_ip_address_rule *ip_rule = NULL;
-
-	node = create_addr_node(dns_conf_address_rule, subnet);
-	if (node == NULL) {
-		return -1;
-	}
-
-	if (node->data == NULL) {
-		ip_rule = malloc(sizeof(*ip_rule));
-		if (ip_rule == NULL) {
-			return -1;
-		}
-
-		node->data = ip_rule;
-		memset(ip_rule, 0, sizeof(*ip_rule));
-	}
-
-	ip_rule = node->data;
-
-	switch (act) {
-	case ACTION_BLACKLIST:
-		ip_rule->blacklist = 1;
-		break;
-	case ACTION_BOGUS:
-		ip_rule->bogus = 1;
-		break;
-	}
-
-	return 0;
-}
-
-int config_blacklist_ip(char *value)
-{
-	return config_iplist_action(value, ACTION_BLACKLIST);
-}
-
-int conf_bogus_nxdomain(char *value)
-{
-	//////////////////////////////////////
-	config_iplist_action(value, ACTION_BOGUS);
-	//////////////////////////////////////
-
-	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)
-{
-	char *file_path = value;
-
-	if (access(file_path, R_OK) != 0) {
-		tlog(TLOG_WARN, "conf file %s is not readable.", file_path);
-		return 0;
-	}
-
-	return load_conf_file(file_path);
-}
-
-struct config_item {
-	const char *item;
-	int (*item_func)(char *value);
-};
-
-struct config_item config_item[] = {
-	{"server-name", config_server_name},
-	{"bind", config_bind},
-	{"bind-tcp", config_bind_tcp},
-	{"server", config_server_udp},
-	{"address", config_address},
-	{"server-tcp", config_server_tcp},
-	{"tcp-idle-time", config_tcp_idle_time},
-	{"server-tls", config_server_tls},
-	{"cache-size", config_cache_size},
-	{"prefetch-domain", config_cache_prefetch_domain},
-	{"log-level", config_log_level},
-	{"log-file", config_log_file},
-	{"log-size", config_log_size},
-	{"log-num", config_log_num},
-	{"audit-enable", config_audit_enable},
-	{"audit-file", config_audit_file},
-	{"audit-size", config_audit_size},
-	{"audit-num", config_audit_num},
-	{"rr-ttl", config_rr_ttl},
-	{"rr-ttl-min", config_rr_ttl_min},
-	{"rr-ttl-max", config_rr_ttl_max},
-	{"force-AAAA-SOA", config_force_AAAA_SOA},
-	{"blacklist-ip", config_blacklist_ip},
-	{"bogus-nxdomain", conf_bogus_nxdomain},
-	{"conf-file", config_addtional_file},
-};
-int config_item_num = sizeof(config_item) / sizeof(struct config_item);
-
-int load_conf_init(void)
-{
-	dns_conf_address_rule = New_Radix();
-	art_tree_init(&dns_conf_domain_rule);
-	if (dns_conf_address_rule == NULL) {
-		return -1;
-	}
-
-	hash_init(dns_conf_bogus_nxdomain.ip_hash);
-	return 0;
-}
-
-void load_exit(void)
-{
-	conf_bogus_nxdomain_destroy();
-	config_domain_destroy();
-	Destroy_Radix(dns_conf_address_rule, config_address_destroy, NULL);
-}
-
-int load_conf_file(const char *file)
-{
-	FILE *fp = NULL;
-	char line[MAX_LINE_LEN];
-	char key[MAX_KEY_LEN];
-	char value[MAX_LINE_LEN];
-	int filed_num = 0;
-	int line_num = 0;
-	int i;
-
-	fp = fopen(file, "r");
-	if (fp == NULL) {
-		tlog(TLOG_ERROR, "config file %s not exist.", file);
-		return -1;
-	}
-
-	while (fgets(line, MAX_LINE_LEN, fp)) {
-		line_num++;
-		filed_num = sscanf(line, "%63s %1023[^\r\n]s", key, value);
-		if (filed_num <= 0) {
-			continue;
-		}
-
-		/* comment, skip */
-		if (key[0] == '#') {
-			continue;
-		}
-
-		/* if field format is not key = value, error */
-		if (filed_num != 2) {
-			goto errout;
-		}
-
-		for (i = 0; i < config_item_num; i++) {
-			if (strncmp(config_item[i].item, key, MAX_KEY_LEN) != 0) {
-				continue;
-			}
-
-			/* call item function */
-			if (config_item[i].item_func(value) != 0) {
-				goto errout;
-			}
-
-			break;
-		}
-	}
-
-	fclose(fp);
-
-	return 0;
-errout:
-	printf("invalid config at file %s:%d, %s", file, line_num, line);
-	tlog(TLOG_ERROR, "invalid config at file %s:%d, %s", file, line_num, line);
-	if (fp) {
-		fclose(fp);
-	}
-	return -1;
-}
-
-int load_conf(const char *file)
-{
-	load_conf_init();
-
-	return load_conf_file(file);
-}

+ 35 - 36
src/dns_client.c

@@ -33,6 +33,8 @@
 #include <netinet/ip.h>
 #include <netinet/ip6.h>
 #include <netinet/ip_icmp.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -42,8 +44,6 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <openssl/ssl.h> 
-#include <openssl/err.h> 
 
 #define DNS_MAX_HOSTNAME 256
 #define DNS_MAX_EVENTS 64
@@ -97,6 +97,7 @@ struct dns_server_info {
 	SSL *ssl;
 	SSL_CTX *ssl_ctx;
 	dns_server_status status;
+	unsigned int result_flag;
 
 	struct dns_server_buff send_buff;
 	struct dns_server_buff recv_buff;
@@ -155,7 +156,6 @@ struct dns_query_struct {
 static struct dns_client client;
 static atomic_t dns_client_sid = ATOMIC_INIT(0);
 
-
 /* get addr info */
 static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int type, int protocol)
 {
@@ -211,7 +211,7 @@ int _dns_client_server_exist(struct addrinfo *gai, dns_server_type_t server_type
 }
 
 /* add dns server information */
-int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type)
+int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type, int result_flag)
 {
 	struct dns_server_info *server_info = NULL;
 
@@ -229,6 +229,7 @@ int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_typ
 	server_info->type = server_type;
 	server_info->fd = 0;
 	server_info->status = DNS_SERVER_STATUS_INIT;
+	server_info->result_flag = result_flag;
 
 	if (gai->ai_addrlen > sizeof(server_info->in6)) {
 		tlog(TLOG_ERROR, "addr len invalid, %d, %zd, %d", gai->ai_addrlen, sizeof(server_info->addr), server_info->ai_family);
@@ -336,7 +337,7 @@ int _dns_client_server_remove(char *server_ip, struct addrinfo *gai, dns_server_
 	return -1;
 }
 
-int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, int operate)
+int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, int result_flag, int operate)
 {
 	char port_s[8];
 	int sock_type;
@@ -370,7 +371,7 @@ int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t serv
 	}
 
 	if (operate == 0) {
-		ret = _dns_client_server_add(server_ip, gai, server_type);
+		ret = _dns_client_server_add(server_ip, gai, server_type, result_flag);
 		if (ret != 0) {
 			goto errout;
 		}
@@ -389,14 +390,14 @@ errout:
 	return -1;
 }
 
-int dns_add_server(char *server_ip, int port, dns_server_type_t server_type)
+int dns_add_server(char *server_ip, int port, dns_server_type_t server_type, int result_flag)
 {
-	return _dns_client_server_operate(server_ip, port, server_type, 0);
+	return _dns_client_server_operate(server_ip, port, server_type, result_flag, 0);
 }
 
 int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type)
 {
-	return _dns_client_server_operate(server_ip, port, server_type, 1);
+	return _dns_client_server_operate(server_ip, port, server_type, 0, 1);
 }
 
 int dns_server_num(void)
@@ -426,7 +427,7 @@ void _dns_client_query_release(struct dns_query_struct *query)
 
 	/* notify caller query end */
 	if (query->callback) {
-		query->callback(query->domain, DNS_QUERY_END, NULL, NULL, 0, query->user_ptr);
+		query->callback(query->domain, DNS_QUERY_END, 0, NULL, NULL, 0, query->user_ptr);
 	}
 
 	/* free resource */
@@ -587,7 +588,7 @@ int _dns_replied_check_add(struct dns_query_struct *dns_query, struct sockaddr *
 	return 0;
 }
 
-static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct sockaddr *from, socklen_t from_len)
+static int _dns_client_recv(struct dns_server_info *server_info, unsigned char *inpacket, int inpacket_len, struct sockaddr *from, socklen_t from_len)
 {
 	int len;
 	int i;
@@ -609,7 +610,7 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
 	if (len != 0) {
 		char host_name[DNS_MAX_CNAME_LEN];
 		tlog(TLOG_ERROR, "decode failed, packet len = %d, tc = %d, id = %d, from = %s\n", inpacket_len, packet->head.tc, packet->head.id,
-			gethost_by_addr(host_name, from, from_len));
+			 gethost_by_addr(host_name, from, from_len));
 		return -1;
 	}
 
@@ -649,12 +650,11 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so
 
 	/* notify caller dns query result */
 	if (query->callback) {
-		ret = query->callback(query->domain, DNS_QUERY_RESULT, packet, inpacket, inpacket_len, query->user_ptr);
-	}
-
-	if (request_num == 0 || ret) {
-		/* if all server replied, or done, stop query, release resource */
-		_dns_client_query_remove(query);
+		ret = query->callback(query->domain, DNS_QUERY_RESULT, server_info->result_flag, packet, inpacket, inpacket_len, query->user_ptr);
+		if (request_num == 0 || ret) {
+			/* if all server replied, or done, stop query, release resource */
+			_dns_client_query_remove(query);
+		}
 	}
 
 	return ret;
@@ -771,7 +771,7 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info)
 		}
 	}
 
-	if(SSL_set_fd(ssl, fd) == 0) {
+	if (SSL_set_fd(ssl, fd) == 0) {
 		tlog(TLOG_ERROR, "ssl set fd failed.");
 		goto errout;
 	}
@@ -844,7 +844,7 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
 	tlog(TLOG_DEBUG, "recv udp, from %s", gethost_by_addr(from_host, (struct sockaddr *)&from, from_len));
 
 	time(&server_info->last_recv);
-	if (_dns_client_recv(inpacket, len, (struct sockaddr *)&from, from_len) != 0) {
+	if (_dns_client_recv(server_info, inpacket, len, (struct sockaddr *)&from, from_len) != 0) {
 		return -1;
 	}
 
@@ -866,7 +866,7 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
 			if (errno == EAGAIN) {
 				return 0;
 			}
-			
+
 			/* FOR GFW */
 			if (errno == ECONNRESET) {
 				goto errout;
@@ -901,9 +901,9 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
 		}
 
 		while (1) {
-			/* tcp result format 
-			* | len (short) | dns query result | 
-			*/
+			/* tcp result format
+			 * | len (short) | dns query result |
+			 */
 			inpacket_data = server_info->recv_buff.data;
 			len = ntohs(*((unsigned short *)(inpacket_data)));
 			if (len <= 0 || len >= DNS_IN_PACKSIZE) {
@@ -920,7 +920,7 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
 			tlog(TLOG_DEBUG, "recv tcp from %s, len = %d", gethost_by_addr(from_host, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen), len);
 
 			/* process result */
-			if (_dns_client_recv(inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
+			if (_dns_client_recv(server_info, inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
 				goto errout;
 			}
 			len += 2;
@@ -1109,9 +1109,9 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
 {
 	X509 *cert = NULL;
 	char peer_CN[256];
-	const EVP_MD        * digest;
-	unsigned char         md[EVP_MAX_MD_SIZE];
-	unsigned int          n;
+	const EVP_MD *digest;
+	unsigned char md[EVP_MAX_MD_SIZE];
+	unsigned int n;
 	char cert_fingerprint[256];
 	int i = 0;
 
@@ -1194,7 +1194,6 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
 			tlog(TLOG_ERROR, "epoll ctl failed.");
 			goto errout;
 		}
-
 	}
 
 	if (event->events & EPOLLIN) {
@@ -1205,7 +1204,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
 			if (errno == EAGAIN) {
 				return 0;
 			}
-			
+
 			/* FOR GFW */
 			if (errno == ECONNRESET) {
 				goto errout;
@@ -1240,9 +1239,9 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
 		}
 
 		while (1) {
-			/* tcp result format 
-			* | len (short) | dns query result | 
-			*/
+			/* tcp result format
+			 * | len (short) | dns query result |
+			 */
 			inpacket_data = server_info->recv_buff.data;
 			len = ntohs(*((unsigned short *)(inpacket_data)));
 			if (len <= 0 || len >= DNS_IN_PACKSIZE) {
@@ -1259,7 +1258,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
 			tlog(TLOG_DEBUG, "recv tcp from %s, len = %d", gethost_by_addr(from_host, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen), len);
 
 			/* process result */
-			if (_dns_client_recv(inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
+			if (_dns_client_recv(server_info, inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) {
 				goto errout;
 			}
 			len += 2;
@@ -1423,7 +1422,7 @@ static int _dns_client_send_tcp(struct dns_server_info *server_info, void *packe
 	unsigned char *inpacket = inpacket_data;
 
 	/* TCP query format
-	 * | len (short) | dns query data | 
+	 * | len (short) | dns query data |
 	 */
 	*((unsigned short *)(inpacket)) = htons(len);
 	memcpy(inpacket + 2, packet, len);
@@ -1451,7 +1450,7 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
 	unsigned char *inpacket = inpacket_data;
 
 	/* TCP query format
-	 * | len (short) | dns query data | 
+	 * | len (short) | dns query data |
 	 */
 	*((unsigned short *)(inpacket)) = htons(len);
 	memcpy(inpacket + 2, packet, len);

+ 4 - 2
src/dns_client.h

@@ -16,10 +16,12 @@ typedef enum dns_result_type {
 	DNS_QUERY_END,
 } dns_result_type;
 
+#define DNSSERVER_FLAG_BLACKLIST_IP (0x1 << 0)
+
 int dns_client_init(void);
 
 /* query result notify function */
-typedef int (*dns_client_callback)(char *domain, dns_result_type rtype, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len, void *user_ptr);
+typedef int (*dns_client_callback)(char *domain, dns_result_type rtype, unsigned int result_flag, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len, void *user_ptr);
 
 /* query domain */
 int dns_client_query(char *domain, int qtype, dns_client_callback callback, void *user_ptr);
@@ -27,7 +29,7 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
 void dns_client_exit(void);
 
 /* add remote dns server */
-int dns_add_server(char *server_ip, int port, dns_server_type_t server_type);
+int dns_add_server(char *server_ip, int port, dns_server_type_t server_type, int result_flag);
 
 /* remove remote dns server */
 int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type);

+ 443 - 0
src/dns_conf.c

@@ -0,0 +1,443 @@
+#include "dns_conf.h"
+#include "list.h"
+#include "rbtree.h"
+#include "tlog.h"
+#include "util.h"
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define DEFAULT_DNS_CACHE_SIZE 512
+
+char dns_conf_server_ip[DNS_MAX_IPLEN];
+char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
+int dns_conf_tcp_idle_time = 120;
+int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
+int dns_conf_prefetch = 0;
+struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
+char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
+int dns_conf_server_num;
+int dns_conf_log_level = TLOG_ERROR;
+char dns_conf_log_file[DNS_MAX_PATH];
+size_t dns_conf_log_size = 1024 * 1024;
+int dns_conf_log_num = 8;
+int dns_conf_audit_enable = 0;
+char dns_conf_audit_file[DNS_MAX_PATH];
+size_t dns_conf_audit_size = 1024 * 1024;
+int dns_conf_audit_num = 2;
+
+art_tree dns_conf_domain_rule;
+radix_tree_t *dns_conf_address_rule;
+
+int dns_conf_rr_ttl;
+int dns_conf_rr_ttl_min;
+int dns_conf_rr_ttl_max;
+int dns_conf_force_AAAA_SOA;
+
+int config_server(int argc, char *argv[], dns_server_type_t type, int default_port)
+{
+	int index = dns_conf_server_num;
+	struct dns_servers *server;
+	int port = -1;
+	char *ip = NULL;
+	int opt = 0;
+	int result_flag = 0;
+	/* clang-format off */
+	static struct option long_options[] = {
+		{"blacklist-ip", 0, 0, 'b'},
+		{0, 0, 0, 0}
+	};
+	/* clang-format on */
+	if (argc <= 1) {
+		tlog(TLOG_ERROR, "invalid parameter.");
+		return -1;
+	}
+
+	ip = argv[1];
+	optind = 1;
+	while (1) {
+		opt = getopt_long_only(argc, argv, "", long_options, NULL);
+		if (opt == -1) {
+			break;
+		}
+
+		switch (opt) {
+			case 'b': {
+				result_flag |= DNSSERVER_FLAG_BLACKLIST_IP;
+				break;
+			}
+		}
+	}
+
+	if (index >= DNS_MAX_SERVERS) {
+		tlog(TLOG_ERROR, "exceeds max server number");
+		return -1;
+	}
+
+	server = &dns_conf_servers[index];
+	/* parse ip, port from ip */
+	if (parse_ip(ip, server->server, &port) != 0) {
+		return -1;
+	}
+
+	/* if port is not defined, set port to default 53 */
+	if (port == PORT_NOT_DEFINED) {
+		port = default_port;
+	}
+
+	server->type = type;
+	server->port = port;
+	server->result_flag = result_flag;
+	dns_conf_server_num++;
+	tlog(TLOG_DEBUG, "add server %s, flag: %X", ip, result_flag);
+
+	return 0;
+}
+
+int config_domain_iter_cb(void *data, const unsigned char *key, uint32_t key_len, void *value)
+{
+	struct dns_domain_rule *domain_rule = value;
+	int i = 0;
+
+	if (domain_rule == NULL) {
+		return 0;
+	}
+
+	for (i = 0; i < DOMAIN_RULE_MAX; i++) {
+		free(domain_rule->rules[i]);
+	}
+
+	free(domain_rule);
+	return 0;
+}
+
+void config_domain_destroy(void)
+{
+	art_iter(&dns_conf_domain_rule, config_domain_iter_cb, 0);
+	art_tree_destroy(&dns_conf_domain_rule);
+}
+
+void config_address_destroy(radix_node_t *node, void *cbctx)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	if (node->data == NULL) {
+		return;
+	}
+
+	free(node->data);
+	node->data = NULL;
+}
+
+int config_domain_rule_add(char *domain, enum domain_rule type, void *rule)
+{
+	struct dns_domain_rule *domain_rule = NULL;
+	struct dns_domain_rule *old_domain_rule = NULL;
+	struct dns_domain_rule *add_domain_rule = 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;
+
+	if (type >= DOMAIN_RULE_MAX) {
+		goto errout;
+	}
+
+	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[type]) {
+		free(domain_rule->rules[type]);
+		domain_rule->rules[type] = NULL;
+	}
+
+	domain_rule->rules[type] = rule;
+
+	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 failed", domain);
+	return 0;
+}
+
+int config_address(void *data, int argc, char *argv[])
+{
+	struct dns_address_IPV4 *address_ipv4 = NULL;
+	struct dns_address_IPV6 *address_ipv6 = NULL;
+	void *address = NULL;
+	char *value = argv[1];
+	char ip[MAX_IP_LEN];
+	char domain[DNS_MAX_CONF_CNAME_LEN];
+	char *begin = NULL;
+	char *end = NULL;
+	int len = 0;
+	int port;
+	struct sockaddr_storage addr;
+	socklen_t addr_len = sizeof(addr);
+	enum domain_rule type = 0;
+
+	begin = strstr(value, "/");
+	if (begin == NULL) {
+		goto errout;
+	}
+
+	begin++;
+	end = strstr(begin, "/");
+	if (end == NULL) {
+		goto errout;
+	}
+
+	/* remove prefix . */
+	while (*begin == '.') {
+		begin++;
+	}
+
+	len = end - begin;
+	memcpy(domain, begin, len);
+	domain[len] = 0;
+
+	if (parse_ip(end + 1, 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;
+		address_ipv4 = malloc(sizeof(*address_ipv4));
+		if (address_ipv4 == NULL) {
+			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)) {
+			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;
+		}
+	} break;
+	default:
+		goto errout;
+	}
+
+	if (config_domain_rule_add(domain, type, address) != 0) {
+		goto errout;
+	}
+
+	return 0;
+errout:
+	if (address) {
+		free(address);
+	}
+
+	tlog(TLOG_ERROR, "add address %s failed", value);
+	return 0;
+}
+
+int config_server_udp(void *data, int argc, char *argv[])
+{
+	return config_server(argc, argv, DNS_SERVER_UDP, DEFAULT_DNS_PORT);
+}
+
+int config_server_tcp(void *data, int argc, char *argv[])
+{
+	return config_server(argc, argv, DNS_SERVER_TCP, DEFAULT_DNS_PORT);
+}
+
+int config_server_tls(void *data, int argc, char *argv[])
+{
+	return config_server(argc, argv, DNS_SERVER_TLS, DEFAULT_DNS_TLS_PORT);
+}
+
+radix_node_t *create_addr_node(radix_tree_t *tree, char *addr)
+{
+	radix_node_t *node;
+	void *p;
+	prefix_t prefix;
+	const char *errmsg = NULL;
+
+	p = prefix_pton(addr, -1, &prefix, &errmsg);
+	if (p == NULL) {
+		return NULL;
+	}
+
+	node = radix_lookup(tree, &prefix);
+	return node;
+}
+
+int config_iplist_rule(char *subnet, enum address_rule rule)
+{
+	radix_node_t *node = NULL;
+	struct dns_ip_address_rule *ip_rule = NULL;
+
+	node = create_addr_node(dns_conf_address_rule, subnet);
+	if (node == NULL) {
+		return -1;
+	}
+
+	if (node->data == NULL) {
+		ip_rule = malloc(sizeof(*ip_rule));
+		if (ip_rule == NULL) {
+			return -1;
+		}
+
+		node->data = ip_rule;
+		memset(ip_rule, 0, sizeof(*ip_rule));
+	}
+
+	ip_rule = node->data;
+
+	switch (rule) {
+	case ADDRESS_RULE_BLACKLIST:
+		ip_rule->blacklist = 1;
+		break;
+	case ADDRESS_RULE_BOGUS:
+		ip_rule->bogus = 1;
+		break;
+	}
+
+	return 0;
+}
+
+int config_blacklist_ip(void *data, int argc, char *argv[])
+{
+	return config_iplist_rule(argv[1], ADDRESS_RULE_BLACKLIST);
+}
+
+int conf_bogus_nxdomain(void *data, int argc, char *argv[])
+{
+	return config_iplist_rule(argv[1], ADDRESS_RULE_BOGUS);
+}
+
+int config_log_level(void *data, int argc, char *argv[])
+{
+	/* read log level and set */
+	char *value = argv[1];
+
+	if (strncmp("debug", value, MAX_LINE_LEN) == 0) {
+		dns_conf_log_level = TLOG_DEBUG;
+	} else if (strncmp("info", value, MAX_LINE_LEN) == 0) {
+		dns_conf_log_level = TLOG_INFO;
+	} else if (strncmp("warn", value, MAX_LINE_LEN) == 0) {
+		dns_conf_log_level = TLOG_WARN;
+	} else if (strncmp("error", value, MAX_LINE_LEN) == 0) {
+		dns_conf_log_level = TLOG_ERROR;
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+struct config_item config_item[] = {
+	CONF_STRING("server-name", (char *)dns_conf_server_name, DNS_MAX_CONF_CNAME_LEN),
+	CONF_STRING("bind", dns_conf_server_ip, DNS_MAX_IPLEN),
+	CONF_STRING("bind-tcp", dns_conf_server_tcp_ip, DNS_MAX_IPLEN),
+	CONF_CUSTOM("server", config_server_udp, NULL),
+	CONF_CUSTOM("server-tcp", config_server_tcp, NULL),
+	CONF_CUSTOM("server-tls", config_server_tls, NULL),
+	CONF_CUSTOM("address", config_address, NULL),
+	CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
+	CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),
+	CONF_YESNO("prefetch-domain", &dns_conf_prefetch),
+	CONF_CUSTOM("log-level", config_log_level, NULL),
+	CONF_STRING("log-file", (char *)dns_conf_log_file, DNS_MAX_PATH),
+	CONF_SIZE("log-size", &dns_conf_log_size, 0, 1024 * 1024 * 1024),
+	CONF_INT("log-num", &dns_conf_log_num, 0, 1024),
+	CONF_YESNO("audit-enable", &dns_conf_audit_enable),
+	CONF_STRING("audit-file", (char *)&dns_conf_audit_file, DNS_MAX_PATH),
+	CONF_SIZE("audit-size", &dns_conf_audit_size, 0, 1024 * 1024 * 1024),
+	CONF_INT("audit-num", &dns_conf_audit_num, 0, 1024),
+	CONF_INT("rr-ttl", &dns_conf_rr_ttl, 0, CONF_INT_MAX),
+	CONF_INT("rr-ttl-min", &dns_conf_rr_ttl_min, 0, CONF_INT_MAX),
+	CONF_INT("rr-ttl-max", &dns_conf_rr_ttl_max, 0, CONF_INT_MAX),
+	CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
+	CONF_CUSTOM("blacklist-ip", config_blacklist_ip, NULL),
+	CONF_CUSTOM("bogus-nxdomain", conf_bogus_nxdomain, NULL),
+	CONF_CUSTOM("conf-file", config_addtional_file, NULL),
+	CONF_END(),
+};
+
+int config_addtional_file(void *data, int argc, char *argv[])
+{
+	char *file_path = argv[1];
+
+	if (access(file_path, R_OK) != 0) {
+		tlog(TLOG_WARN, "conf file %s is not readable.", file_path);
+		return 0;
+	}
+
+	return load_conf(file_path, config_item);
+}
+
+int _dns_server_load_conf_init(void)
+{
+	dns_conf_address_rule = New_Radix();
+	art_tree_init(&dns_conf_domain_rule);
+	if (dns_conf_address_rule == NULL) {
+		return -1;
+	}
+
+	return 0;
+}
+
+void dns_server_load_exit(void)
+{
+	config_domain_destroy();
+	Destroy_Radix(dns_conf_address_rule, config_address_destroy, NULL);
+}
+
+int dns_server_load_conf(const char *file)
+{
+	_dns_server_load_conf_init();
+
+	return load_conf(file, config_item);
+}

+ 31 - 23
src/conf.h → src/dns_conf.h

@@ -1,13 +1,14 @@
 #ifndef _DNS_CONF
 #define _DNS_CONF
 
-#include "list.h"
 #include "art.h"
-#include "radix.h"
+#include "conf.h"
 #include "dns.h"
 #include "dns_client.h"
 #include "hash.h"
 #include "hashtable.h"
+#include "list.h"
+#include "radix.h"
 
 #define DNS_MAX_SERVERS 32
 #define DNS_MAX_IPLEN 64
@@ -19,21 +20,31 @@
 #define SMARTDNS_LOG_FILE "/var/log/smartdns.log"
 #define SMARTDNS_AUDIT_FILE "/var/log/smartdns-audit.log"
 
+enum domain_rule {
+	DOMAIN_RULE_ADDRESS_IPV4 = 1,
+	DOMAIN_RULE_ADDRESS_IPV6 = 2,
+	DOMAIN_RULE_MAX,
+};
+
+struct dns_address_IPV4 {
+	unsigned char ipv4_addr[DNS_RR_A_LEN];
+};
+
+struct dns_address_IPV6 {
+	unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
+};
+
+struct dns_domain_rule {
+	void *rules[DOMAIN_RULE_MAX];
+};
+
 struct dns_servers {
 	char server[DNS_MAX_IPLEN];
 	unsigned short port;
+	unsigned int result_flag;
 	dns_server_type_t type;
 };
 
-struct dns_address {
-	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];
-	};
-};
-
 /* ip address lists of domain */
 struct dns_bogus_ip_address {
 	struct hlist_node node;
@@ -45,13 +56,12 @@ struct dns_bogus_ip_address {
 	};
 };
 
-enum address_action {
-	ACTION_BLACKLIST = 1,
-	ACTION_BOGUS = 2,
+enum address_rule {
+	ADDRESS_RULE_BLACKLIST = 1,
+	ADDRESS_RULE_BOGUS = 2,
 };
 
-struct dns_ip_address_rule 
-{
+struct dns_ip_address_rule {
 	unsigned int blacklist : 1;
 	unsigned int bogus : 1;
 };
@@ -68,16 +78,14 @@ extern int dns_conf_prefetch;
 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;
+extern size_t dns_conf_log_size;
 extern int dns_conf_log_num;
 
 extern int dns_conf_audit_enable;
 extern char dns_conf_audit_file[DNS_MAX_PATH];
-extern int dns_conf_audit_size;
+extern size_t dns_conf_audit_size;
 extern int dns_conf_audit_num;
 
 extern char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
@@ -89,10 +97,10 @@ extern int dns_conf_rr_ttl_min;
 extern int dns_conf_rr_ttl_max;
 extern int dns_conf_force_AAAA_SOA;
 
-int dns_bogus_nxdomain_exists(unsigned char *ip, dns_type_t addr_type);
+void dns_server_load_exit(void);
 
-int load_conf(const char *file);
+int dns_server_load_conf(const char *file);
 
-void load_exit(void);
+extern int config_addtional_file(void *data, int argc, char *argv[]);
 
 #endif // !_DNS_CONF

+ 96 - 105
src/dns_server.c

@@ -18,7 +18,7 @@
 #define _GNU_SOURCE
 #include "dns_server.h"
 #include "atomic.h"
-#include "conf.h"
+#include "dns_conf.h"
 #include "dns.h"
 #include "dns_cache.h"
 #include "dns_client.h"
@@ -85,7 +85,6 @@ struct dns_server {
 	struct list_head client_list;
 };
 
-
 /* ip address lists of domain */
 struct dns_ip_address {
 	struct hlist_node node;
@@ -153,9 +152,11 @@ struct dns_request {
 	int prefetch;
 
 	pthread_mutex_t ip_map_lock;
-	
+
 	int ip_map_num;
 	DECLARE_HASHTABLE(ip_map, 4);
+
+	struct dns_domain_rule *domain_rule;
 };
 
 static struct dns_server server;
@@ -180,13 +181,12 @@ static void _dns_server_audit_log(struct dns_request *request)
 	}
 
 	if (request->qtype == DNS_T_AAAA) {
-		snprintf(req_result, sizeof(req_result), "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
-			 request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5],
-			 request->ipv6_addr[6], request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11],
-			 request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
+		snprintf(req_result, sizeof(req_result), "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->ipv6_addr[0],
+				 request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5], request->ipv6_addr[6],
+				 request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11], request->ipv6_addr[12],
+				 request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
 	} else if (request->qtype == DNS_T_A) {
-		snprintf(req_result, sizeof(req_result), "%d.%d.%d.%d", request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2],
-			 request->ipv4_addr[3]);
+		snprintf(req_result, sizeof(req_result), "%d.%d.%d.%d", request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
 	} else {
 		return;
 	}
@@ -324,7 +324,7 @@ static int _dns_server_reply_tcp(struct dns_server_conn *client, void *packet, u
 	unsigned char *inpacket = inpacket_data;
 
 	/* TCP query format
-	 * | len (short) | dns query data | 
+	 * | len (short) | dns query data |
 	 */
 	*((unsigned short *)(inpacket)) = htons(len);
 	memcpy(inpacket + 2, packet, len);
@@ -372,8 +372,6 @@ static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpac
 		ret = -1;
 	}
 
-	_dns_server_client_release(client);
-
 	return ret;
 }
 
@@ -667,23 +665,7 @@ 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_ip_rule_check(struct dns_request *request, unsigned char *addr, int addr_len, dns_type_t addr_type)
+static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char *addr, int addr_len, dns_type_t addr_type, int result_flag)
 {
 	prefix_t prefix;
 	radix_node_t *node = NULL;
@@ -695,7 +677,7 @@ static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char
 
 	node = radix_search_best(dns_conf_address_rule, &prefix);
 	if (node == NULL) {
-		return - 1;
+		return -1;
 	}
 
 	if (node->data == NULL) {
@@ -703,11 +685,26 @@ static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char
 	}
 
 	rule = node->data;
+	if (rule->bogus) {
+		goto match;
+	}
 
+	if (rule->blacklist) {
+		if (result_flag & DNSSERVER_FLAG_BLACKLIST_IP) {
+			goto match;
+		}
+	}
+
+	return -1;
+
+match:
+	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)
+static int _dns_server_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet, unsigned int result_flag)
 {
 	int ttl;
 	char name[DNS_MAX_CNAME_LEN] = {0};
@@ -741,15 +738,9 @@ 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]);
 
-				if (_dns_server_ip_rule_check(request, addr, 4, DNS_T_A) == 0) {
-					_dns_server_request_release(request);
-					break;
-				}
-
-				/* bogus ip address, skip */
-				if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_A) == 0) {
+				/* ip rule check */
+				if (_dns_server_ip_rule_check(request, addr, 4, DNS_T_A, result_flag) == 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;
 				}
 
@@ -799,20 +790,11 @@ 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]);
 
-				if (_dns_server_ip_rule_check(request, addr, 16, DNS_T_A) == 0) {
+				if (_dns_server_ip_rule_check(request, addr, 16, DNS_T_AAAA, result_flag) == 0) {
 					_dns_server_request_release(request);
 					break;
 				}
 
-				/* 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;
@@ -886,10 +868,11 @@ static int dns_server_update_reply_packet_id(struct dns_request *request, unsign
 	return 0;
 }
 
-static int dns_server_resolve_callback(char *domain, dns_result_type rtype, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len,
+static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsigned int result_flag, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len,
 									   void *user_ptr)
 {
 	struct dns_request *request = user_ptr;
+	struct dns_server_conn *client = request->client;
 	int ip_num = 0;
 
 	if (request == NULL) {
@@ -900,9 +883,10 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, stru
 		if (request->passthrough) {
 			dns_server_update_reply_packet_id(request, inpacket, inpacket_len);
 			_dns_reply_inpacket(request, inpacket, inpacket_len);
-			return -1;
+			return 0;
 		}
-		_dns_server_process_answer(request, domain, packet);
+
+		_dns_server_process_answer(request, domain, packet, result_flag);
 		return 0;
 	} else if (rtype == DNS_QUERY_ERR) {
 		tlog(TLOG_ERROR, "request faield, %s", domain);
@@ -921,6 +905,7 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, stru
 			_dns_server_request_remove(request);
 		}
 		_dns_server_request_release(request);
+		_dns_server_client_release(client);
 	}
 
 	return 0;
@@ -1023,35 +1008,26 @@ static int _dns_server_reply_SOA(int rcode, struct dns_request *request, struct
 static void _dns_server_log_rule(char *domain, unsigned char *rule_key, int rule_key_len)
 {
 	char rule_name[DNS_MAX_CNAME_LEN];
+
+	if (rule_key_len <= 0) {
+		return;
+	}
+
 	reverse_string(rule_name, (char *)rule_key, rule_key_len);
-	rule_name[rule_key_len - 1] = 0;
+	rule_name[rule_key_len] = 0;
 	tlog(TLOG_INFO, "RULE-MATCH, domain: %s, rule: %s", domain, rule_name);
 }
 
-static struct dns_address *_dns_server_get_address_by_domain(char *domain, int qtype)
+static struct dns_domain_rule *_dns_server_get_domain_rule(char *domain)
 {
 	int domain_len;
 	char domain_key[DNS_MAX_CNAME_LEN];
-	char type = '4';
-	unsigned char matched_key[DNS_MAX_CNAME_LEN];
 	int matched_key_len = DNS_MAX_CNAME_LEN;
-	struct dns_address *address = NULL;
-
-	switch (qtype) {
-	case DNS_T_A:
-		type = '4';
-		break;
-	case DNS_T_AAAA:
-		type = '6';
-		break;
-	default:
-		return NULL;
-	}
+	unsigned char matched_key[DNS_MAX_CNAME_LEN];
+	struct dns_domain_rule *domain_rule = NULL;
 
 	domain_len = strlen(domain);
-	reverse_string(domain_key + 1, domain, domain_len);
-	domain_key[0] = type;
-	domain_len++;
+	reverse_string(domain_key, domain, domain_len);
 	domain_key[domain_len] = '.';
 	domain_len++;
 	domain_key[domain_len] = 0;
@@ -1060,37 +1036,47 @@ static struct dns_address *_dns_server_get_address_by_domain(char *domain, int q
 		return art_substring(&dns_conf_domain_rule, (unsigned char *)domain_key, domain_len, NULL, NULL);
 	}
 
-	address = art_substring(&dns_conf_domain_rule, (unsigned char *)domain_key, domain_len, matched_key, &matched_key_len);
-	if (address == NULL) {
+	domain_rule = art_substring(&dns_conf_domain_rule, (unsigned char *)domain_key, domain_len, matched_key, &matched_key_len);
+	if (domain_rule == NULL) {
+		return NULL;
+	}
+
+	if (matched_key_len <= 0) {
 		return NULL;
 	}
 
+	matched_key_len--;
+	matched_key[matched_key_len] = 0;
 	_dns_server_log_rule(domain, matched_key, matched_key_len);
 
-	return address;
+	return domain_rule;
 }
 
 static int _dns_server_process_address(struct dns_request *request, struct dns_packet *packet)
 {
-	struct dns_address *address = NULL;
-
-	address = _dns_server_get_address_by_domain(request->domain, request->qtype);
-	if (address == NULL) {
-		goto errout;
-	}
+	struct dns_address_IPV4 *address_ipv4 = NULL;
+	struct dns_address_IPV6 *address_ipv6 = NULL;
 
-	if (request->qtype != address->addr_type) {
+	if (request->domain_rule == NULL) {
 		goto errout;
 	}
 
 	switch (request->qtype) {
 	case DNS_T_A:
-		memcpy(request->ipv4_addr, address->ipv4_addr, DNS_RR_A_LEN);
+		if (request->domain_rule->rules[DOMAIN_RULE_ADDRESS_IPV4] == NULL) {
+			goto errout;
+		}
+		address_ipv4 = request->domain_rule->rules[DOMAIN_RULE_ADDRESS_IPV4];
+		memcpy(request->ipv4_addr, address_ipv4->ipv4_addr, DNS_RR_A_LEN);
 		request->ttl_v4 = 600;
 		request->has_ipv4 = 1;
 		break;
 	case DNS_T_AAAA:
-		memcpy(request->ipv6_addr, address->ipv6_addr, DNS_RR_AAAA_LEN);
+		if (request->domain_rule->rules[DOMAIN_RULE_ADDRESS_IPV6] == NULL) {
+			goto errout;
+		}
+		address_ipv6 = request->domain_rule->rules[DOMAIN_RULE_ADDRESS_IPV6];
+		memcpy(request->ipv6_addr, address_ipv6->ipv6_addr, DNS_RR_AAAA_LEN);
 		request->ttl_v6 = 600;
 		request->has_ipv6 = 1;
 		break;
@@ -1174,9 +1160,9 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
 		goto errout;
 	}
 
-	tlog(TLOG_DEBUG, "request qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d, tc = %d, rd = %d, ra = %d, rcode = %d\n", packet->head.qdcount,
-		 packet->head.ancount, packet->head.nscount, packet->head.nrcount, inpacket_len, packet->head.id, packet->head.tc, packet->head.rd, packet->head.ra,
-		 packet->head.rcode);
+	tlog(TLOG_DEBUG, "request qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d, tc = %d, rd = %d, ra = %d, rcode = %d\n",
+		 packet->head.qdcount, packet->head.ancount, packet->head.nscount, packet->head.nrcount, inpacket_len, packet->head.id, packet->head.tc,
+		 packet->head.rd, packet->head.ra, packet->head.rcode);
 
 	if (packet->head.qr != DNS_QR_QUERY) {
 		goto errout;
@@ -1187,6 +1173,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
 		tlog(TLOG_ERROR, "malloc failed.\n");
 		goto errout;
 	}
+
 	memset(request, 0, sizeof(*request));
 	pthread_mutex_init(&request->ip_map_lock, 0);
 	atomic_set(&request->adblock, 0);
@@ -1219,12 +1206,13 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
 		request->qtype = qtype;
 	}
 
+	request->domain_rule = _dns_server_get_domain_rule(request->domain);
+
 	switch (qtype) {
 	case DNS_T_PTR:
 		ret = _dns_server_process_ptr(request, packet);
 		if (ret == 0) {
-			free(request);
-			return ret;
+			goto clean_exit;
 		} else {
 			request->passthrough = 1;
 		}
@@ -1234,8 +1222,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
 	case DNS_T_AAAA:
 		if (dns_conf_force_AAAA_SOA == 1) {
 			_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
-			free(request);
-			return 0;
+			goto clean_exit;
 		}
 		break;
 	default:
@@ -1245,13 +1232,11 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
 	}
 
 	if (_dns_server_process_address(request, packet) == 0) {
-		free(request);
-		return 0;
+		goto clean_exit;
 	}
 
 	if (_dns_server_process_cache(request, packet) == 0) {
-		free(request);
-		return 0;
+		goto clean_exit;
 	}
 
 	tlog(TLOG_INFO, "query server %s from %s, qtype = %d\n", request->domain, gethost_by_addr(name, (struct sockaddr *)from, from_len), qtype);
@@ -1265,6 +1250,14 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
 	request->send_tick = get_tick_count();
 	dns_client_query(request->domain, qtype, dns_server_resolve_callback, request);
 
+	return 0;
+clean_exit:
+	if (request) {
+		free(request);
+	}
+
+	_dns_server_client_release(client);
+
 	return 0;
 errout:
 	if (request) {
@@ -1339,6 +1332,7 @@ static void _dns_server_client_touch(struct dns_server_conn *client)
 static int _dns_server_client_close(struct dns_server_conn *client)
 {
 	if (client->fd > 0) {
+		epoll_ctl(server.epoll_fd, EPOLL_CTL_DEL, client->fd, NULL);
 		close(client->fd);
 		client->fd = -1;
 	}
@@ -1356,7 +1350,7 @@ static int _dns_server_accept(struct dns_server_conn *dnsserver, struct epoll_ev
 	struct dns_server_conn *client = NULL;
 	socklen_t addr_len = sizeof(addr);
 	int fd = -1;
-	
+
 	fd = accept4(dnsserver->fd, (struct sockaddr *)&addr, &addr_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
 	if (fd < 0) {
 		return -1;
@@ -1408,8 +1402,7 @@ int _dns_server_tcp_recv(struct dns_server_conn *dnsserver)
 			return 0;
 		}
 
-		len = recv(dnsserver->fd, dnsserver->recvbuff.buf + dnsserver->recvbuff.size, 
-			sizeof(dnsserver->recvbuff.buf) - dnsserver->recvbuff.size, 0);
+		len = recv(dnsserver->fd, dnsserver->recvbuff.buf + dnsserver->recvbuff.size, sizeof(dnsserver->recvbuff.buf) - dnsserver->recvbuff.size, 0);
 		if (len < 0) {
 			if (errno == EAGAIN) {
 				return 1;
@@ -1439,7 +1432,7 @@ int _dns_server_tcp_process_one_request(struct dns_server_conn *dnsserver)
 		}
 
 		request_len = ntohs(*((unsigned short *)(dnsserver->recvbuff.buf + proceed_len)));
-		
+
 		if (request_len >= sizeof(dnsserver->recvbuff.buf)) {
 			tlog(TLOG_ERROR, "request length is invalid.");
 			return -1;
@@ -1511,7 +1504,7 @@ int _dns_server_tcp_send(struct dns_server_conn *client)
 				return 1;
 			}
 			return -1;
-		} else if (len == 0 ) {
+		} else if (len == 0) {
 			break;
 		}
 
@@ -1539,7 +1532,7 @@ static int _dns_server_process_tcp(struct dns_server_conn *dnsserver, struct epo
 		if (_dns_server_tcp_process_requests(dnsserver) != 0) {
 			_dns_server_client_close(dnsserver);
 		}
-	} 
+	}
 
 	if (event->events & EPOLLOUT) {
 		if (_dns_server_tcp_send(dnsserver) != 0) {
@@ -1638,7 +1631,6 @@ void _dns_server_tcp_idle_check(void)
 	}
 }
 
-
 void _dns_server_period_run_second(void)
 {
 	static unsigned int sec = 0;
@@ -1721,6 +1713,7 @@ int dns_server_run(void)
 		if (num == 0) {
 			continue;
 		}
+
 		for (i = 0; i < num; i++) {
 			struct epoll_event *event = &events[i];
 			struct dns_server_conn *dnsserver = event->data.ptr;
@@ -1771,7 +1764,7 @@ int _dns_server_start_udp(void)
 	if (server.udp_server.fd <= 0) {
 		return 0;
 	}
-	
+
 	memset(&event, 0, sizeof(event));
 	event.events = EPOLLIN;
 	event.data.ptr = &server.udp_server;
@@ -1790,7 +1783,7 @@ int _dns_server_start_tcp(void)
 	if (server.tcp_server.fd <= 0) {
 		return 0;
 	}
-	
+
 	memset(&event, 0, sizeof(event));
 	event.events = EPOLLIN;
 	event.data.ptr = &server.tcp_server;
@@ -1816,7 +1809,6 @@ int dns_server_start(void)
 	return 0;
 }
 
-
 int _dns_create_socket(const char *host_ip, int type)
 {
 	int fd = -1;
@@ -1896,7 +1888,6 @@ int _dns_server_socket(void)
 		if (fd_tcp < 0) {
 			goto errout;
 		}
-
 	}
 
 	server.udp_server.fd = fd_udp;

+ 116 - 0
src/include/conf.h

@@ -0,0 +1,116 @@
+#ifndef _GENERIC_CONF_H
+#define _GENERIC_CONF_H
+
+#include <unistd.h>
+
+#define MAX_LINE_LEN 1024
+#define MAX_KEY_LEN 64
+#define CONF_INT_MAX (~(1 << 31))
+#define CONF_INT_MIN (1 << 31)
+
+struct config_item {
+	const char *item;
+	int (*item_func)(const char *item, void *data, int argc, char *argv[]);
+	void *data;
+};
+
+struct config_item_custom {
+	void *custom_data;
+	int (*custom_func)(void *data, int argc, char *argv[]);
+};
+
+struct config_item_int {
+	int *data;
+	int min;
+	int max;
+};
+
+struct config_item_string {
+	char *data;
+	size_t size;
+};
+
+struct config_item_yesno {
+	int *data;
+};
+
+struct config_item_size {
+	size_t *data;
+	size_t min;
+	size_t max;
+};
+
+#define CONF_INT(key, value, min_value, max_value)                                                                                                             \
+	{                                                                                                                                                          \
+		key, conf_int, &(struct config_item_int)                                                                                                               \
+		{                                                                                                                                                      \
+			.data = value, .min = min_value, .max = max_value                                                                                                  \
+		}                                                                                                                                                      \
+	}
+#define CONF_STRING(key, value, len_value)                                                                                                                     \
+	{                                                                                                                                                          \
+		key, conf_string, &(struct config_item_string)                                                                                                         \
+		{                                                                                                                                                      \
+			.data = value, .size = len_value                                                                                                                   \
+		}                                                                                                                                                      \
+	}
+#define CONF_YESNO(key, value)                                                                                                                                 \
+	{                                                                                                                                                          \
+		key, conf_yesno, &(struct config_item_yesno)                                                                                                           \
+		{                                                                                                                                                      \
+			.data = value                                                                                                                                      \
+		}                                                                                                                                                      \
+	}
+#define CONF_SIZE(key, value, min_value, max_value)                                                                                                            \
+	{                                                                                                                                                          \
+		key, conf_size, &(struct config_item_size)                                                                                                             \
+		{                                                                                                                                                      \
+			.data = value, .min = min_value, .max = max_value                                                                                                  \
+		}                                                                                                                                                      \
+	}
+/*
+ * func: int (*func)(void *data, int argc, char *argv[]);
+ */
+#define CONF_CUSTOM(key, func, data)                                                                                                                           \
+	{                                                                                                                                                          \
+		key, conf_custom, &(struct config_item_custom)                                                                                                         \
+		{                                                                                                                                                      \
+			.custom_data = data, .custom_func = func                                                                                                           \
+		}                                                                                                                                                      \
+	}
+
+#define CONF_END()                                                                                                                                             \
+	{                                                                                                                                                          \
+		0, 0, 0                                                                                                                                                \
+	}
+
+extern int conf_custom(const char *item, void *data, int argc, char *argv[]);
+
+extern int conf_int(const char *item, void *data, int argc, char *argv[]);
+
+extern int conf_string(const char *item, void *data, int argc, char *argv[]);
+
+extern int conf_yesno(const char *item, void *data, int argc, char *argv[]);
+
+extern int conf_size(const char *item, void *data, int argc, char *argv[]);
+
+/*
+ * Example:
+ *  int num = 0;
+ * 
+ *  struct config_item itmes [] = {
+ *       CONF_INT("CONF_NUM", &num, -1, 10),
+ *       CONF_END();
+ *  }
+ *
+ *  load_conf(file, items);
+ *
+ */
+
+int load_conf(const char *file, struct config_item items[]);
+
+int load_conf_get_line_count(void);
+
+void load_exit(void);
+
+#endif // !_GENERIC_CONF_H

+ 263 - 0
src/lib/conf.c

@@ -0,0 +1,263 @@
+#include "conf.h"
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+__thread int line_no;
+
+int conf_custom(const char *item, void *data, int argc, char *argv[])
+{
+	struct config_item_custom *item_custom = data;
+	return item_custom->custom_func(item_custom->custom_data, argc, argv);
+}
+
+int conf_int(const char *item, void *data, int argc, char *argv[])
+{
+	struct config_item_int *item_int = data;
+	int value = 0;
+	if (argc < 2) {
+		return -1;
+	}
+
+	value = atoi(argv[1]);
+
+	if (value < item_int->min) {
+		value = item_int->min;
+	} else if (value > item_int->max) {
+		value = item_int->max;
+	}
+
+	*(item_int->data) = value;
+
+	return 0;
+}
+
+int conf_string(const char *item, void *data, int argc, char *argv[])
+{
+	struct config_item_string *item_string = data;
+
+	if (argc < 2) {
+		return -1;
+	}
+
+	strncpy(item_string->data, argv[1], item_string->size);
+
+	return 0;
+}
+
+int conf_yesno(const char *item, void *data, int argc, char *argv[])
+{
+	struct config_item_yesno *item_yesno = data;
+	int yes = 0;
+
+	if (argc < 2) {
+		return -1;
+	}
+
+	char *value = argv[1];
+	if (strncmp("yes", value, sizeof("yes")) == 0 || strncmp("YES", value, sizeof("YES")) == 0) {
+		yes = 1;
+	} else if (strncmp("no", value, sizeof("no")) == 0 || strncmp("NO", value, sizeof("NO")) == 0) {
+		yes = 0;
+	}
+
+	*(item_yesno->data) = yes;
+
+	return 0;
+}
+
+int conf_size(const char *item, void *data, int argc, char *argv[])
+{
+	/* read dns cache size */
+	int base = 1;
+	size_t size = 0;
+	int num = 0;
+	struct config_item_size *item_size = data;
+	char *value = argv[1];
+
+	if (strstr(value, "k") || strstr(value, "K")) {
+		base = 1024;
+	} else if (strstr(value, "m") || strstr(value, "M")) {
+		base = 1024 * 1024;
+	} else if (strstr(value, "g") || strstr(value, "G")) {
+		base = 1024 * 1024 * 1024;
+	}
+
+	num = atoi(value);
+	if (num < 0) {
+		return -1;
+	}
+
+	size = num * base;
+	if (size > item_size->max) {
+		size = item_size->max;
+	} else if (size < item_size->min) {
+		size = item_size->min;
+	}
+
+	*(item_size->data) = size;
+
+	return 0;
+}
+
+void conf_getopt_reset(void)
+{
+	static struct option long_options[] = {{"-", 0, 0, 0}, {0, 0, 0, 0}};
+	int argc = 2;
+	char *argv[3] = {"reset", "", 0};
+
+	optind = 1;
+	opterr = 0;
+	getopt_long(argc, argv, "", long_options, NULL);
+	optind = 1;
+	opterr = 0;
+}
+
+int conf_parse_args(char *key, char *value, int *argc, char **argv)
+{
+	char *start = NULL;
+	char *ptr = value;
+	int count = 0;
+	int sep_flag = ' ';
+
+	argv[0] = key;
+	count++;
+
+	while (*ptr != '\0') {
+		if (*ptr == '\\') {
+			char *tmp = ptr + 1;
+			while (*tmp != '\0') {
+				*(tmp - 1) = *tmp;
+				tmp++;
+			}
+			ptr++;
+			continue;
+		}
+
+		if (*ptr == '"' && start == NULL) {
+			sep_flag = '"';
+			start = NULL;
+		}
+
+		if (*ptr != sep_flag && start == NULL) {
+			start = ptr;
+			ptr++;
+			continue;
+		}
+
+		if (*ptr == sep_flag && start == NULL) {
+			ptr++;
+			continue;
+		}
+
+		if (*ptr == sep_flag && start) {
+			argv[count] = start;
+			*ptr = '\0';
+			ptr++;
+			start = ptr;
+			count++;
+			sep_flag = ' ';
+			start = NULL;
+			continue;
+		}
+
+		ptr++;
+	}
+
+	if (start != ptr && start) {
+		argv[count] = start;
+		count++;
+	}
+
+	*argc = count;
+	argv[count + 1] = 0;
+
+	return 0;
+}
+
+void load_exit(void)
+{
+	return;
+}
+
+int load_conf_get_line_count(void)
+{
+	return line_no;
+}
+
+int load_conf_file(const char *file, struct config_item *items)
+{
+	FILE *fp = NULL;
+	char line[MAX_LINE_LEN];
+	char key[MAX_KEY_LEN];
+	char value[MAX_LINE_LEN];
+	int filed_num = 0;
+	int i;
+	int argc;
+	char *argv[1024];
+
+	fp = fopen(file, "r");
+	if (fp == NULL) {
+		return -1;
+	}
+
+	line_no = 0;
+	while (fgets(line, MAX_LINE_LEN, fp)) {
+		line_no++;
+		filed_num = sscanf(line, "%63s %1023[^\r\n]s", key, value);
+		if (filed_num <= 0) {
+			continue;
+		}
+
+		/* comment, skip */
+		if (key[0] == '#') {
+			continue;
+		}
+
+		/* if field format is not key = value, error */
+		if (filed_num != 2) {
+			goto errout;
+		}
+
+		for (i = 0;; i++) {
+			if (items[i].item == NULL) {
+				break;
+			}
+
+			if (strncmp(items[i].item, key, MAX_KEY_LEN) != 0) {
+				continue;
+			}
+
+			if (conf_parse_args(key, value, &argc, argv) != 0) {
+				continue;
+			}
+
+			conf_getopt_reset();
+			/* call item function */
+			if (items[i].item_func(items[i].item, items[i].data, argc, argv) != 0) {
+				conf_getopt_reset();
+				goto errout;
+			}
+
+			conf_getopt_reset();
+
+			break;
+		}
+	}
+
+	fclose(fp);
+
+	return 0;
+errout:
+	if (fp) {
+		fclose(fp);
+	}
+	return -1;
+}
+
+int load_conf(const char *file, struct config_item items[])
+{
+	return load_conf_file(file, items);
+}

+ 21 - 14
src/smartdns.c

@@ -19,7 +19,7 @@
 #define _GNU_SOURCE
 #include "art.h"
 #include "atomic.h"
-#include "conf.h"
+#include "dns_conf.h"
 #include "dns_client.h"
 #include "dns_server.h"
 #include "fast_ping.h"
@@ -31,14 +31,14 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <libgen.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
 
 #define RESOLVE_FILE "/etc/resolv.conf"
 #define MAX_LINE_LEN 1024
@@ -55,6 +55,7 @@ void help(void)
 		"  -f            run forground.\n"
 		"  -c [conf]     config file.\n"
 		"  -p [pid]      pid file path\n"
+		"  -S            ignore segment fault signal.\n"
 		"  -h            show this help message.\n"
 
 		"Online help: http://pymumu.github.io/smartdns"
@@ -119,7 +120,7 @@ int smartdns_add_servers(void)
 	int i = 0;
 	int ret = 0;
 	for (i = 0; i < dns_conf_server_num; i++) {
-		ret = dns_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type);
+		ret = dns_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type, dns_conf_servers[i].result_flag);
 		if (ret != 0) {
 			tlog(TLOG_ERROR, "add server failed, %s:%d", dns_conf_servers[i].server, dns_conf_servers[i].port);
 			return -1;
@@ -206,7 +207,7 @@ int smartdns_init(void)
 		goto errout;
 	}
 
-	//tlog_setlogscreen(1); 
+	//tlog_setlogscreen(1);
 	tlog_setlevel(dns_conf_log_level);
 
 	if (smartdns_init_ssl() != 0) {
@@ -262,7 +263,7 @@ void smartdns_exit(void)
 	fast_ping_exit();
 	smartdns_destroy_ssl();
 	tlog_exit();
-	load_exit();
+	dns_server_load_exit();
 }
 
 void sig_handle(int sig)
@@ -287,11 +288,12 @@ int main(int argc, char *argv[])
 	int opt;
 	char config_file[MAX_LINE_LEN];
 	char pid_file[MAX_LINE_LEN];
+	int signal_ignore = 0;
 
 	strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN);
 	strncpy(pid_file, SMARTDNS_PID_FILE, MAX_LINE_LEN);
 
-	while ((opt = getopt(argc, argv, "fhc:p:")) != -1) {
+	while ((opt = getopt(argc, argv, "fhc:p:S")) != -1) {
 		switch (opt) {
 		case 'f':
 			is_forground = 1;
@@ -302,6 +304,9 @@ int main(int argc, char *argv[])
 		case 'p':
 			snprintf(pid_file, sizeof(pid_file), "%s", optarg);
 			break;
+		case 'S':
+			signal_ignore = 1;
+			break;
 		case 'h':
 			help();
 			return 1;
@@ -315,14 +320,16 @@ int main(int argc, char *argv[])
 		}
 	}
 
-	signal(SIGABRT, sig_handle);
-	signal(SIGPIPE, SIG_IGN);
-	signal(SIGBUS, sig_handle);
-	signal(SIGSEGV, sig_handle);
-	signal(SIGILL, sig_handle);
-	signal(SIGFPE, sig_handle);
+	if (signal_ignore == 0) {
+		signal(SIGABRT, sig_handle);
+		signal(SIGPIPE, SIG_IGN);
+		signal(SIGBUS, sig_handle);
+		signal(SIGSEGV, sig_handle);
+		signal(SIGILL, sig_handle);
+		signal(SIGFPE, sig_handle);
+	}
 
-	if (load_conf(config_file) != 0) {
+	if (dns_server_load_conf(config_file) != 0) {
 	}
 
 	if (create_pid_file(pid_file) != 0) {

+ 5 - 0
src/util.c

@@ -155,6 +155,11 @@ int set_fd_nonblock(int fd, int nonblock)
 char *reverse_string(char *output, char *input, int len)
 {
 	char *begin = output;
+	if (len <= 0) {
+		*output = 0;
+		return output;
+	}
+	
 	len--;
 	while (len >= 0) {
 		*output = *(input + len);

+ 2 - 0
src/util.h

@@ -20,4 +20,6 @@ int set_fd_nonblock(int fd, int nonblock);
 
 char *reverse_string(char *output, char *input, int len);
 
+void print_stack(void);
+
 #endif