Nick Peng vor 7 Jahren
Ursprung
Commit
ec83f75582
9 geänderte Dateien mit 977 neuen und 765 gelöschten Zeilen
  1. 1 1
      Makefile
  2. 4 9
      conf.c
  3. 1 1
      conf.h
  4. 121 22
      dns_server.c
  5. 832 722
      fast_ping.c
  6. 1 2
      smartdns.c
  7. 3 3
      smartdns.conf
  8. 13 4
      util.c
  9. 1 1
      util.h

+ 1 - 1
Makefile

@@ -10,7 +10,7 @@ CXXFLAGS +=-Iinclude
 .PHONY: all
 
 all: $(BIN)
-
+ 
 $(BIN) : $(OBJS)
 	$(CC) $(OBJS) -o $@ -lpthread 
 

+ 4 - 9
conf.c

@@ -11,19 +11,14 @@
 
 #define DEFAULT_DNS_CACHE_SIZE 512
 
-int dns_conf_port = DEFAULT_DNS_PORT;
+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];
 int dns_conf_server_num;
 
-int config_port(char *value)
+int config_bind(char *value)
 {
-	int port = atoi(value);
-	if (port <= 0 || port >= 65535) {
-		return -1;
-	}
-
-	dns_conf_port = port;
+	strncpy(dns_conf_server_ip, value, DNS_MAX_IPLEN);
 
 	return 0;
 }
@@ -88,7 +83,7 @@ struct config_item {
 };
 
 struct config_item config_item[] = {
-	{"port", config_port},
+	{"bind", config_bind},
 	{"server", config_server_udp},
     {"server-tcp", config_server_tcp},
     {"server-http", config_server_http},

+ 1 - 1
conf.h

@@ -17,7 +17,7 @@ struct dns_servers {
 	dns_conf_server_type_t type;
 };
 
-extern int dns_conf_port;
+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;

+ 121 - 22
dns_server.c

@@ -55,8 +55,8 @@ struct dns_server {
 
 	int fd;
 
-	pthread_mutex_t map_lock;
-	DECLARE_HASHTABLE(hostmap, 6);
+	pthread_mutex_t request_list_lock;
+	struct list_head request_list;
 };
 
 struct dns_ip_address {
@@ -71,7 +71,7 @@ struct dns_ip_address {
 
 struct dns_request {
 	atomic_t refcnt;
-	struct hlist_node map;
+	struct list_head list;
 	char domain[DNS_MAX_CNAME_LEN];
 	struct dns_head head;
 	unsigned long send_tick;
@@ -86,6 +86,9 @@ struct dns_request {
 		struct sockaddr addr;
 	};
 
+	int has_ping_result;
+	int has_ping_tcp;
+
 	int has_ptr;
 
 	int has_cname;
@@ -106,13 +109,12 @@ struct dns_request {
 
 	int passthrough;
 
+	pthread_mutex_t ip_map_lock;
 	DECLARE_HASHTABLE(ip_map, 4);
 };
 
 static struct dns_server server;
 
-void _dns_server_period_run() {}
-
 static int _dns_server_forward_request(unsigned char *inpacket, int inpacket_len)
 {
 	tlog(TLOG_ERROR, "forward request.\n");
@@ -255,10 +257,10 @@ int _dns_server_request_complete(struct dns_request *request)
 		tlog(TLOG_INFO, "result: %s, rcode: %d,  %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0], request->ipv4_addr[1],
 			 request->ipv4_addr[2], request->ipv4_addr[3]);
 	} else if (request->qtype == DNS_T_AAAA) {
-		tlog(TLOG_INFO, "result :%s, rcode: %d,  %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x", request->domain, request->rcode, 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]);
+		tlog(TLOG_INFO, "result :%s, rcode: %d,  %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->domain, request->rcode,
+			 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]);
 	}
 
 	_dns_reply(request);
@@ -266,7 +268,7 @@ int _dns_server_request_complete(struct dns_request *request)
 	return ret;
 }
 
-void _dns_server_request_release(struct dns_request *request)
+void _dns_server_request_release_lock(struct dns_request *request, int locked)
 {
 	struct dns_ip_address *addr_map;
 	struct hlist_node *tmp;
@@ -281,16 +283,30 @@ void _dns_server_request_release(struct dns_request *request)
 		return;
 	}
 
+	if (locked == 0) {
+		pthread_mutex_lock(&server.request_list_lock);
+		list_del(&request->list);
+		pthread_mutex_unlock(&server.request_list_lock);
+	} else {
+		list_del(&request->list);
+	}
+
 	_dns_server_request_complete(request);
 	hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
 	{
 		hash_del(&addr_map->node);
 		free(addr_map);
 	}
+	pthread_mutex_destroy(&request->ip_map_lock);
 	memset(request, 0, sizeof(*request));
 	free(request);
 }
 
+void _dns_server_request_release(struct dns_request *request)
+{
+	_dns_server_request_release_lock(request, 0);
+}
+
 void _dns_server_request_get(struct dns_request *request)
 {
 	atomic_inc(&request->refcnt);
@@ -343,6 +359,7 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
 		break;
 	}
 	if (result == PING_RESULT_RESPONSE) {
+		request->has_ping_result = 1;
 		tlog(TLOG_DEBUG, "from %15s: seq=%d time=%d\n", host, seqno, rtt);
 	} else {
 		tlog(TLOG_DEBUG, "from %15s: seq=%d timeout\n", host, seqno);
@@ -374,18 +391,22 @@ int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr,
 	}
 
 	key = jhash(addr, addr_len, 0);
+	pthread_mutex_lock(&request->ip_map_lock);
 	hash_for_each_possible(request->ip_map, addr_map, node, key)
 	{
 		if (addr_type == DNS_T_A) {
 			if (memcmp(addr_map->ipv4_addr, addr, addr_len) == 0) {
+				pthread_mutex_unlock(&request->ip_map_lock);
 				return -1;
 			}
 		} else if (addr_type == DNS_T_AAAA) {
 			if (memcmp(addr_map->ipv6_addr, addr, addr_len) == 0) {
+				pthread_mutex_unlock(&request->ip_map_lock);
 				return -1;
 			}
 		}
 	}
+	pthread_mutex_unlock(&request->ip_map_lock);
 
 	addr_map = malloc(sizeof(*addr_map));
 	if (addr_map == NULL) {
@@ -418,7 +439,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++) {
@@ -467,11 +487,12 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
 					break;
 				}
 
-				tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x", 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]);
+				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]);
+
+				sprintf(name, "%.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]);
 
-				sprintf(name, "%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x", 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 (fast_ping_start(name, 1, 0, 1000, _dns_server_ping_result, request) == NULL) {
 					_dns_server_request_release(request);
 				}
@@ -625,6 +646,7 @@ static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct so
 
 	request = malloc(sizeof(*request));
 	memset(request, 0, sizeof(*request));
+	pthread_mutex_init(&request->ip_map_lock, 0);
 	request->ttl_v4 = -1;
 	request->ttl_v6 = -1;
 	request->rcode = DNS_RC_SERVFAIL;
@@ -676,6 +698,11 @@ static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct so
 	}
 
 	tlog(TLOG_INFO, "query server %s from %s, qtype = %d\n", request->domain, gethost_by_addr(name, (struct sockaddr *)from, from_len), qtype);
+
+	pthread_mutex_lock(&server.request_list_lock);
+	list_add_tail(&request->list, &server.request_list);
+	pthread_mutex_unlock(&server.request_list_lock);
+
 	_dns_server_request_get(request);
 	request->send_tick = get_tick_count();
 	dns_client_query(request->domain, qtype, dns_server_resolve_callback, request);
@@ -705,13 +732,74 @@ static int _dns_server_process(unsigned long now)
 	return _dns_server_recv(inpacket, len, &from, from_len);
 }
 
+void _dns_server_tcp_ping_check(struct dns_request *request)
+{
+	struct dns_ip_address *addr_map;
+	int bucket = 0;
+	char name[DNS_MAX_CNAME_LEN] = {0};
+	char ip[DNS_MAX_CNAME_LEN] = {0};
+
+	if (request->has_ping_result) {
+		return;
+	}
+
+	if (request->has_ping_tcp) {
+		return;
+	}
+
+	pthread_mutex_lock(&request->ip_map_lock);
+	hash_for_each(request->ip_map, bucket, addr_map, node)
+	{
+		switch (addr_map->addr_type) {
+		case DNS_T_A: {
+			_dns_server_request_get(request);
+			sprintf(ip, "%d.%d.%d.%d:80", addr_map->ipv4_addr[0], addr_map->ipv4_addr[1], addr_map->ipv4_addr[2], addr_map->ipv4_addr[3]);
+			if (fast_ping_start(ip, 1, 0, 1000, _dns_server_ping_result, request) == NULL) {
+				_dns_server_request_release_lock(request, 1);
+			}
+		} break;
+		case DNS_T_AAAA: {
+			_dns_server_request_get(request);
+			sprintf(name, "[%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x]:80", addr_map->ipv6_addr[0], addr_map->ipv6_addr[1],
+					addr_map->ipv6_addr[2], addr_map->ipv6_addr[3], addr_map->ipv6_addr[4], addr_map->ipv6_addr[5], addr_map->ipv6_addr[6],
+					addr_map->ipv6_addr[7], addr_map->ipv6_addr[8], addr_map->ipv6_addr[9], addr_map->ipv6_addr[10], addr_map->ipv6_addr[11],
+					addr_map->ipv6_addr[12], addr_map->ipv6_addr[13], addr_map->ipv6_addr[14], addr_map->ipv6_addr[15]);
+
+			if (fast_ping_start(name, 1, 0, 1000, _dns_server_ping_result, request) == NULL) {
+				_dns_server_request_release_lock(request, 1);
+			}
+		} break;
+		default:
+			break;
+		}
+	}
+	pthread_mutex_unlock(&request->ip_map_lock);
+
+	request->has_ping_tcp = 1;
+}
+
+void _dns_server_period_run()
+{
+	struct dns_request *request, *tmp;
+	unsigned long now = get_tick_count();
+
+	pthread_mutex_lock(&server.request_list_lock);
+	list_for_each_entry_safe(request, tmp, &server.request_list, list)
+	{
+		if (request->send_tick < now - 500 && request->has_ping_tcp == 0) {
+			_dns_server_tcp_ping_check(request);
+		}
+	}
+	pthread_mutex_unlock(&server.request_list_lock);
+}
+
 int dns_server_run(void)
 {
 	struct epoll_event events[DNS_MAX_EVENTS + 1];
 	int num;
 	int i;
 	unsigned long now = {0};
-	int sleep = 1000;
+	int sleep = 100;
 	int sleep_time = 0;
 	unsigned long expect_time = 0;
 
@@ -798,9 +886,20 @@ int dns_server_socket(void)
 	int fd = -1;
 	struct addrinfo *gai = NULL;
 	char port_str[8];
+	char ip[MAX_IP_LEN];
+	int port;
+	char *host = NULL;
+
+	if (parse_ip(dns_conf_server_ip, ip, &port) == 0) {
+		host = ip;
+	}
+
+	if (port <= 0) {
+		port = DEFAULT_DNS_PORT;
+	}
 
-	snprintf(port_str, sizeof(port_str), "%d", dns_conf_port);
-	gai = _dns_server_getaddr(NULL, port_str, SOCK_DGRAM, 0);
+	snprintf(port_str, sizeof(port_str), "%d", port);
+	gai = _dns_server_getaddr(host, port_str, SOCK_DGRAM, 0);
 	if (gai == NULL) {
 		tlog(TLOG_ERROR, "get address failed.\n");
 		goto errout;
@@ -857,8 +956,8 @@ int dns_server_init(void)
 		goto errout;
 	}
 
-	pthread_mutex_init(&server.map_lock, 0);
-	hash_init(server.hostmap);
+	pthread_mutex_init(&server.request_list_lock, 0);
+	INIT_LIST_HEAD(&server.request_list);
 	server.epoll_fd = epollfd;
 	server.fd = fd;
 	server.run = 1;
@@ -880,7 +979,7 @@ errout:
 		close(epollfd);
 	}
 
-	pthread_mutex_destroy(&server.map_lock);
+	pthread_mutex_destroy(&server.request_list_lock);
 
 	return -1;
 }
@@ -894,5 +993,5 @@ void dns_server_exit(void)
 		server.fd = -1;
 	}
 
-	pthread_mutex_destroy(&server.map_lock);
+	pthread_mutex_destroy(&server.request_list_lock);
 }

+ 832 - 722
fast_ping.c

@@ -23,6 +23,7 @@
 #include "util.h"
 #include <arpa/inet.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <linux/filter.h>
 #include <netdb.h>
 #include <netinet/icmp6.h>
@@ -44,61 +45,63 @@
 #define ICMP_INPACKET_SIZE 1024
 
 struct fast_ping_packet_msg {
-	struct timeval tv;
-	unsigned int sid;
-	unsigned int seq;
+    struct timeval tv;
+    unsigned int sid;
+    unsigned int seq;
 };
 
 struct fast_ping_packet {
-	union {
-		struct icmp icmp;
-		struct icmp6_hdr icmp6;
-	};
-	struct fast_ping_packet_msg msg;
+    union {
+        struct icmp icmp;
+        struct icmp6_hdr icmp6;
+    };
+    struct fast_ping_packet_msg msg;
 };
 
 struct ping_host_struct {
-	atomic_t ref;
-	struct hlist_node host_node;
-	struct hlist_node addr_node;
-	FAST_PING_TYPE type;
-
-	void *userptr;
-	fast_ping_result ping_callback;
-	char host[PING_MAX_HOSTLEN];
-
-	int fd;
-	unsigned int seq;
-	struct timeval last;
-	int interval;
-	int timeout;
-	int count;
-	int send;
-	unsigned int sid;
-	union {
-		struct sockaddr addr;
-		struct sockaddr_in6 in6;
-		struct sockaddr_in in;
-	};
-	socklen_t addr_len;
-	struct fast_ping_packet packet;
+    atomic_t ref;
+    struct hlist_node host_node;
+    struct hlist_node addr_node;
+    FAST_PING_TYPE type;
+
+    void *userptr;
+    fast_ping_result ping_callback;
+    char host[PING_MAX_HOSTLEN];
+
+    int fd;
+    unsigned int seq;
+    struct timeval last;
+    int interval;
+    int timeout;
+    int count;
+    int send;
+    unsigned int sid;
+    unsigned short port;
+    unsigned short ss_family;
+    union {
+        struct sockaddr addr;
+        struct sockaddr_in6 in6;
+        struct sockaddr_in in;
+    };
+    socklen_t addr_len;
+    struct fast_ping_packet packet;
 };
 
 struct fast_ping_struct {
-	int run;
-	pthread_t tid;
-	pthread_mutex_t lock;
-	unsigned short ident;
-
-	int epoll_fd;
-	int fd_icmp;
-	struct ping_host_struct icmp_host;
-	int fd_icmp6;
-	struct ping_host_struct icmp6_host;
-
-	pthread_mutex_t map_lock;
-	DECLARE_HASHTABLE(hostmap, 6);
-	DECLARE_HASHTABLE(addrmap, 6);
+    int run;
+    pthread_t tid;
+    pthread_mutex_t lock;
+    unsigned short ident;
+
+    int epoll_fd;
+    int fd_icmp;
+    struct ping_host_struct icmp_host;
+    int fd_icmp6;
+    struct ping_host_struct icmp6_host;
+
+    pthread_mutex_t map_lock;
+    DECLARE_HASHTABLE(hostmap, 6);
+    DECLARE_HASHTABLE(addrmap, 6);
 };
 
 static struct fast_ping_struct ping;
@@ -106,806 +109,913 @@ static atomic_t ping_sid = ATOMIC_INIT(0);
 
 uint16_t _fast_ping_checksum(uint16_t *header, size_t len)
 {
-	uint32_t sum = 0;
-	int i;
+    uint32_t sum = 0;
+    int i;
 
-	for (i = 0; i < len / sizeof(uint16_t); i++) {
-		sum += ntohs(header[i]);
-	}
+    for (i = 0; i < len / sizeof(uint16_t); i++) {
+        sum += ntohs(header[i]);
+    }
 
-	return htons(~((sum >> 16) + (sum & 0xffff)));
+    return htons(~((sum >> 16) + (sum & 0xffff)));
 }
 
 void _fast_ping_install_filter_v6(int sock)
 {
-	struct icmp6_filter icmp6_filter;
-	ICMP6_FILTER_SETBLOCKALL(&icmp6_filter);
-	ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &icmp6_filter);
-	setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_filter, sizeof(struct icmp6_filter));
-
-	static int once;
-	static struct sock_filter insns[] = {
-		BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4),                       /* Load icmp echo ident */
-		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1),           /* Ours? */
-		BPF_STMT(BPF_RET | BPF_K, ~0U),                              /* Yes, it passes. */
-		BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0),                       /* Load icmp type */
-		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */
-		BPF_STMT(BPF_RET | BPF_K, ~0U),                              /* No. It passes. This must not happen. */
-		BPF_STMT(BPF_RET | BPF_K, 0),                                /* Echo with wrong ident. Reject. */
-	};
-	static struct sock_fprog filter = {sizeof insns / sizeof(insns[0]), insns};
-
-	if (once) {
-		return;
-	}
-	once = 1;
-
-	/* Patch bpflet for current identifier. */
-	insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
-
-	if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
-		perror("WARNING: failed to install socket filter\n");
-	}
+    struct icmp6_filter icmp6_filter;
+    ICMP6_FILTER_SETBLOCKALL(&icmp6_filter);
+    ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &icmp6_filter);
+    setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &icmp6_filter, sizeof(struct icmp6_filter));
+
+    static int once;
+    static struct sock_filter insns[] = {
+        BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4), /* Load icmp echo ident */
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
+        BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
+        BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0), /* Load icmp type */
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */
+        BPF_STMT(BPF_RET | BPF_K, ~0U), /* No. It passes. This must not happen. */
+        BPF_STMT(BPF_RET | BPF_K, 0), /* Echo with wrong ident. Reject. */
+    };
+    static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns };
+
+    if (once) {
+        return;
+    }
+    once = 1;
+
+    /* Patch bpflet for current identifier. */
+    insns[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
+
+    if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
+        perror("WARNING: failed to install socket filter\n");
+    }
 }
 
 void _fast_ping_install_filter_v4(int sock)
 {
-	static int once;
-	static struct sock_filter insns[] = {
-		BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0),                    /* Skip IP header. F..g BSD... Look into ping6. */
-		BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4),                     /* Load icmp echo ident */
-		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1),         /* Ours? */
-		BPF_STMT(BPF_RET | BPF_K, ~0U),                            /* Yes, it passes. */
-		BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),                     /* Load icmp type */
-		BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
-		BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFF),                      /* No. It passes. */
-		BPF_STMT(BPF_RET | BPF_K, 0)                               /* Echo with wrong ident. Reject. */
-	};
-
-	static struct sock_fprog filter = {sizeof insns / sizeof(insns[0]), insns};
-
-	if (once) {
-		return;
-	}
-	once = 1;
-
-	/* Patch bpflet for current identifier. */
-	insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
-
-	if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
-		perror("WARNING: failed to install socket filter\n");
-	}
+    static int once;
+    static struct sock_filter insns[] = {
+        BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */
+        BPF_STMT(BPF_LD | BPF_H | BPF_IND, 4), /* Load icmp echo ident */
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */
+        BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */
+        BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0), /* Load icmp type */
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */
+        BPF_STMT(BPF_RET | BPF_K, 0xFFFFFFF), /* No. It passes. */
+        BPF_STMT(BPF_RET | BPF_K, 0) /* Echo with wrong ident. Reject. */
+    };
+
+    static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns };
+
+    if (once) {
+        return;
+    }
+    once = 1;
+
+    /* Patch bpflet for current identifier. */
+    insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htons(getpid()), 0, 1);
+
+    if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
+        perror("WARNING: failed to install socket filter\n");
+    }
 }
 
-static struct addrinfo *_fast_ping_getaddr(const char *host, int type, int protocol)
+static struct addrinfo *_fast_ping_getaddr(const char *host, const char *port, int type, int protocol)
 {
-	struct addrinfo hints;
-	struct addrinfo *result = NULL;
-
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = AF_UNSPEC;
-	hints.ai_socktype = type;
-	hints.ai_protocol = protocol;
-	if (getaddrinfo(host, NULL, &hints, &result) != 0) {
-		tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
-		goto errout;
-	}
-
-	return result;
+    struct addrinfo hints;
+    struct addrinfo *result = NULL;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = type;
+    hints.ai_protocol = protocol;
+    if (getaddrinfo(host, port, &hints, &result) != 0) {
+        tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
+        goto errout;
+    }
+
+    return result;
 errout:
-	if (result) {
-		freeaddrinfo(result);
-	}
-	return NULL;
+    if (result) {
+        freeaddrinfo(result);
+    }
+    return NULL;
 }
 
 static int _fast_ping_getdomain(const char *host)
 {
-	struct addrinfo hints;
-	struct addrinfo *result = NULL;
-	int domain = -1;
-
-	memset(&hints, 0, sizeof(hints));
-	hints.ai_family = AF_UNSPEC;
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_protocol = 0;
-	if (getaddrinfo(host, NULL, &hints, &result) != 0) {
-		tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
-		goto errout;
-	}
+    struct addrinfo hints;
+    struct addrinfo *result = NULL;
+    int domain = -1;
 
-	domain = result->ai_family;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_protocol = 0;
+    if (getaddrinfo(host, NULL, &hints, &result) != 0) {
+        tlog(TLOG_ERROR, "get addr info failed. %s\n", strerror(errno));
+        goto errout;
+    }
 
-	freeaddrinfo(result);
+    domain = result->ai_family;
 
-	return domain;
+    freeaddrinfo(result);
+
+    return domain;
 errout:
-	if (result) {
-		freeaddrinfo(result);
-	}
-	return -1;
+    if (result) {
+        freeaddrinfo(result);
+    }
+    return -1;
 }
 
 static void _fast_ping_host_get(struct ping_host_struct *ping_host)
 {
-	atomic_inc(&ping_host->ref);
+    atomic_inc(&ping_host->ref);
 }
 
-static void _fast_ping_host_put(struct ping_host_struct *ping_host)
+static void _fast_ping_host_put_locked(struct ping_host_struct *ping_host, int locked)
 {
-	pthread_mutex_lock(&ping.map_lock);
-	if (atomic_dec_and_test(&ping_host->ref)) {
-		hash_del(&ping_host->host_node);
-		hash_del(&ping_host->addr_node);
-	} else {
-		ping_host = NULL;
-	}
-	pthread_mutex_unlock(&ping.map_lock);
-
-	if (ping_host == NULL) {
-		return;
-	}
-
-	struct timeval tv;
-	tv.tv_sec = 0;
-	tv.tv_usec = 0;
-
-	ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tv, ping_host->userptr);
-
-	free(ping_host);
+    if (locked) {
+        if (atomic_dec_and_test(&ping_host->ref)) {
+            hash_del(&ping_host->host_node);
+            hash_del(&ping_host->addr_node);
+        } else {
+            ping_host = NULL;
+        }
+    } else {
+        pthread_mutex_lock(&ping.map_lock);
+        if (atomic_dec_and_test(&ping_host->ref)) {
+            hash_del(&ping_host->host_node);
+            hash_del(&ping_host->addr_node);
+        } else {
+            ping_host = NULL;
+        }
+        pthread_mutex_unlock(&ping.map_lock);
+    }
+
+    if (ping_host == NULL) {
+        return;
+    }
+
+    struct timeval tv;
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+
+    ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tv, ping_host->userptr);
+
+    if (ping_host->fd > 0) {
+        close(ping_host->fd);
+		ping_host->fd = -1;
+	}
+
+    free(ping_host);
 }
 
-static void _fast_ping_host_put_locked(struct ping_host_struct *ping_host)
+static void _fast_ping_host_put(struct ping_host_struct *ping_host)
 {
-	if (atomic_dec_and_test(&ping_host->ref)) {
-		hash_del(&ping_host->host_node);
-		hash_del(&ping_host->addr_node);
-	} else {
-		ping_host = NULL;
-	}
-
-	if (ping_host == NULL) {
-		return;
-	}
-
-	struct timeval tv;
-	tv.tv_sec = 0;
-	tv.tv_usec = 0;
-
-	ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, ping_host->seq, &tv, ping_host->userptr);
-
-	free(ping_host);
+    _fast_ping_host_put_locked(ping_host, 0);
 }
 
 static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
 {
-	struct fast_ping_packet *packet = &ping_host->packet;
-	struct icmp6_hdr *icmp6 = &packet->icmp6;
-	int len = 0;
-
-	ping_host->seq++;
-	memset(icmp6, 0, sizeof(*icmp6));
-	icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
-	icmp6->icmp6_code = 0;
-	icmp6->icmp6_cksum = 0;
-	icmp6->icmp6_id = getpid();
-	icmp6->icmp6_seq = htons(ping_host->seq);
-
-	gettimeofday(&packet->msg.tv, 0);
-	packet->msg.sid = ping_host->sid;
-	packet->msg.seq = ping_host->seq;
-	icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
-
-	len = sendto(ping_host->fd, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
-	if (len < 0 || len != sizeof(struct fast_ping_packet)) {
-		if (errno == ENETUNREACH) {
-			goto errout;
-		}
-		char ping_host_name[PING_MAX_HOSTLEN];
-		tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
-			 strerror(errno));
-		goto errout;
-	}
-
-	return 0;
+    struct fast_ping_packet *packet = &ping_host->packet;
+    struct icmp6_hdr *icmp6 = &packet->icmp6;
+    int len = 0;
+
+    ping_host->seq++;
+    memset(icmp6, 0, sizeof(*icmp6));
+    icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
+    icmp6->icmp6_code = 0;
+    icmp6->icmp6_cksum = 0;
+    icmp6->icmp6_id = getpid();
+    icmp6->icmp6_seq = htons(ping_host->seq);
+
+    gettimeofday(&packet->msg.tv, 0);
+    packet->msg.sid = ping_host->sid;
+    packet->msg.seq = ping_host->seq;
+    icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
+
+    len = sendto(ping.fd_icmp6, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
+    if (len < 0 || len != sizeof(struct fast_ping_packet)) {
+        if (errno == ENETUNREACH) {
+            goto errout;
+        }
+        char ping_host_name[PING_MAX_HOSTLEN];
+        tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
+            strerror(errno));
+        goto errout;
+    }
+
+    return 0;
 
 errout:
-	return -1;
+    return -1;
 }
 
 static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
 {
-	struct fast_ping_packet *packet = &ping_host->packet;
-	struct icmp *icmp = &packet->icmp;
-	int len;
-
-	ping_host->seq++;
-	memset(icmp, 0, sizeof(*icmp));
-	icmp->icmp_type = ICMP_ECHO;
-	icmp->icmp_code = 0;
-	icmp->icmp_cksum = 0;
-	icmp->icmp_id = ping.ident;
-	icmp->icmp_seq = htons(ping_host->seq);
-
-	gettimeofday(&packet->msg.tv, 0);
-	packet->msg.sid = ping_host->sid;
-	packet->msg.seq = ping_host->seq;
-	icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
-
-	len = sendto(ping_host->fd, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
-	if (len < 0 || len != sizeof(struct fast_ping_packet)) {
-		if (errno == ENETUNREACH) {
-			goto errout;
-		}
-		char ping_host_name[PING_MAX_HOSTLEN];
-		tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
-			 strerror(errno));
-		goto errout;
-	}
-
-	return 0;
+    struct fast_ping_packet *packet = &ping_host->packet;
+    struct icmp *icmp = &packet->icmp;
+    int len;
+
+    ping_host->seq++;
+    memset(icmp, 0, sizeof(*icmp));
+    icmp->icmp_type = ICMP_ECHO;
+    icmp->icmp_code = 0;
+    icmp->icmp_cksum = 0;
+    icmp->icmp_id = ping.ident;
+    icmp->icmp_seq = htons(ping_host->seq);
+
+    gettimeofday(&packet->msg.tv, 0);
+    packet->msg.sid = ping_host->sid;
+    packet->msg.seq = ping_host->seq;
+    icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
+
+    len = sendto(ping.fd_icmp, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
+    if (len < 0 || len != sizeof(struct fast_ping_packet)) {
+        if (errno == ENETUNREACH) {
+            goto errout;
+        }
+        char ping_host_name[PING_MAX_HOSTLEN];
+        tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
+            strerror(errno));
+        goto errout;
+    }
+
+    return 0;
 
 errout:
-	return -1;
+    return -1;
 }
 
-static int _fast_ping_sendping(struct ping_host_struct *ping_host)
+static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host)
 {
-	int ret = -1;
+    struct epoll_event event;
+    int flags;
+    int fd = 0;
+
+    fd = socket(ping_host->ss_family, SOCK_STREAM, 0);
+    if (fd < 0) {
+        goto errout;
+    }
+
+    flags = fcntl(fd, F_GETFL, 0);
+    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+    ping_host->seq++;
+    if (connect(fd, (struct sockaddr *)&ping_host->addr, ping_host->addr_len) != 0) {
+        if (errno != EINPROGRESS) {
+            char ping_host_name[PING_MAX_HOSTLEN];
+            if (errno == ENETUNREACH) {
+				goto errout;
+			}
+            tlog(TLOG_ERROR, "connect %s, id %d, %s", gethost_by_addr(ping_host_name, (struct sockaddr *)&ping_host->addr, ping_host->addr_len), ping_host->sid,
+                strerror(errno));
+            goto errout;
+        }
+    }
 
-	if (ping_host->type == FAST_PING_ICMP) {
-		ret = _fast_ping_sendping_v4(ping_host);
-	} else if (ping_host->type == FAST_PING_ICMP6) {
-		ret = _fast_ping_sendping_v6(ping_host);
-	}
+    event.events = EPOLLIN | EPOLLOUT;
+    event.data.ptr = ping_host;
+    if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
+        goto errout;
+    }
 
-	ping_host->send = 1;
-	gettimeofday(&ping_host->last, 0);
+    if (ping_host->fd > 0) {
+        close(ping_host->fd);
+    }
+    ping_host->fd = fd;
 
-	if (ret != 0) {
-		return ret;
-	}
+    return 0;
 
-	return 0;
+errout:
+    if (fd > 0) {
+        close(fd);
+    }
+    return -1;
 }
 
-static int _fast_ping_create_sock(FAST_PING_TYPE type)
+static int _fast_ping_sendping(struct ping_host_struct *ping_host)
 {
-	int fd = -1;
-	struct ping_host_struct *icmp_host = NULL;
-	struct epoll_event event;
-	int buffsize = 64 * 1024;
-	socklen_t optlen = sizeof(buffsize);
-
-	switch (type) {
-	case FAST_PING_ICMP:
-		fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
-		if (fd < 0) {
-			tlog(TLOG_ERROR, "create icmp socket failed.\n");
-			goto errout;
-		}
-		_fast_ping_install_filter_v4(fd);
-		icmp_host = &ping.icmp_host;
-		break;
-	case FAST_PING_ICMP6:
-		fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
-		if (fd < 0) {
-			tlog(TLOG_ERROR, "create icmp socket failed.\n");
-			goto errout;
-		}
-		_fast_ping_install_filter_v6(fd);
-		icmp_host = &ping.icmp6_host;
-		break;
-	default:
-		return -1;
-	}
+    int ret = -1;
 
-	setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&buffsize, optlen);
-	setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&buffsize, optlen);
+    if (ping_host->type == FAST_PING_ICMP) {
+        ret = _fast_ping_sendping_v4(ping_host);
+    } else if (ping_host->type == FAST_PING_ICMP6) {
+        ret = _fast_ping_sendping_v6(ping_host);
+    } else if (ping_host->type == FAST_PING_TCP) {
+        ret = _fast_ping_sendping_tcp(ping_host);
+    }
 
-	event.events = EPOLLIN;
-	event.data.ptr = icmp_host;
-	if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
-		goto errout;
-	}
+    ping_host->send = 1;
+    gettimeofday(&ping_host->last, 0);
 
-	icmp_host->fd = fd;
-	icmp_host->type = type;
-	return fd;
+    if (ret != 0) {
+        return ret;
+    }
 
-errout:
-	close(fd);
-	return -1;
+    return 0;
 }
 
-static int _fast_ping_create_icmp(FAST_PING_TYPE type)
+static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
 {
-	int fd = 0;
-	int *set_fd = NULL;
-
-	pthread_mutex_lock(&ping.lock);
-	switch (type) {
-	case FAST_PING_ICMP:
-		set_fd = &ping.fd_icmp;
-		break;
-	case FAST_PING_ICMP6:
-		set_fd = &ping.fd_icmp6;
-		break;
-	default:
-		goto errout;
-		break;
-	}
-
-	if (*set_fd > 0) {
-		goto out;
-	}
+    int fd = -1;
+    struct ping_host_struct *icmp_host = NULL;
+    struct epoll_event event;
+    int buffsize = 64 * 1024;
+    socklen_t optlen = sizeof(buffsize);
+
+    switch (type) {
+    case FAST_PING_ICMP:
+        fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+        if (fd < 0) {
+            tlog(TLOG_ERROR, "create icmp socket failed.\n");
+            goto errout;
+        }
+        _fast_ping_install_filter_v4(fd);
+        icmp_host = &ping.icmp_host;
+        break;
+    case FAST_PING_ICMP6:
+        fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+        if (fd < 0) {
+            tlog(TLOG_ERROR, "create icmp socket failed.\n");
+            goto errout;
+        }
+        _fast_ping_install_filter_v6(fd);
+        icmp_host = &ping.icmp6_host;
+        break;
+    default:
+        return -1;
+    }
+
+    setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&buffsize, optlen);
+    setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&buffsize, optlen);
+
+    event.events = EPOLLIN;
+    event.data.ptr = icmp_host;
+    if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
+        goto errout;
+    }
+
+    icmp_host->fd = fd;
+    icmp_host->type = type;
+    return fd;
 
-	fd = _fast_ping_create_sock(type);
-	if (fd < 0) {
-		goto errout;
-	}
+errout:
+    close(fd);
+    return -1;
+}
 
-	*set_fd = fd;
+static int _fast_ping_create_icmp(FAST_PING_TYPE type)
+{
+    int fd = 0;
+    int *set_fd = NULL;
+
+    pthread_mutex_lock(&ping.lock);
+    switch (type) {
+    case FAST_PING_ICMP:
+        set_fd = &ping.fd_icmp;
+        break;
+    case FAST_PING_ICMP6:
+        set_fd = &ping.fd_icmp6;
+        break;
+    default:
+        goto errout;
+        break;
+    }
+
+    if (*set_fd > 0) {
+        goto out;
+    }
+
+    fd = _fast_ping_create_icmp_sock(type);
+    if (fd < 0) {
+        goto errout;
+    }
+
+    *set_fd = fd;
 out:
-	pthread_mutex_unlock(&ping.lock);
-	return *set_fd;
+    pthread_mutex_unlock(&ping.lock);
+    return *set_fd;
 errout:
-	if (fd > 0) {
-		close(fd);
-	}
-	pthread_mutex_unlock(&ping.lock);
-	return -1;
+    if (fd > 0) {
+        close(fd);
+    }
+    pthread_mutex_unlock(&ping.lock);
+    return -1;
 }
 
 void fast_ping_print_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno,
-							struct timeval *tv, void *userptr)
+    struct timeval *tv, void *userptr)
 {
-	if (result == PING_RESULT_RESPONSE) {
-		double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0;
-		tlog(TLOG_INFO, "from %15s: seq=%d time=%.3f\n", host, seqno, rtt);
-	} else if (result == PING_RESULT_TIMEOUT) {
-		tlog(TLOG_INFO, "from %15s: seq=%d timeout\n", host, seqno);
-	}
+    if (result == PING_RESULT_RESPONSE) {
+        double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0;
+        tlog(TLOG_INFO, "from %15s: seq=%d time=%.3f\n", host, seqno, rtt);
+    } else if (result == PING_RESULT_TIMEOUT) {
+        tlog(TLOG_INFO, "from %15s: seq=%d timeout\n", host, seqno);
+    }
 }
 
 struct ping_host_struct *fast_ping_start(const char *host, int count, int interval, int timeout, fast_ping_result ping_callback, void *userptr)
 {
-	struct ping_host_struct *ping_host = NULL;
-	struct addrinfo *gai = NULL;
-	int domain = -1;
-	int icmp_proto = 0;
-	uint32_t hostkey;
-	uint32_t addrkey;
-	int fd = -1;
-	FAST_PING_TYPE type;
-
-	domain = _fast_ping_getdomain(host);
-	if (domain < 0) {
-		return NULL;
-	}
-
-	switch (domain) {
-	case AF_INET:
-		icmp_proto = IPPROTO_ICMP;
-		type = FAST_PING_ICMP;
-		break;
-	case AF_INET6:
-		icmp_proto = IPPROTO_ICMPV6;
-		type = FAST_PING_ICMP6;
-		break;
-	default:
-		return NULL;
-		break;
-	}
-
-	fd = _fast_ping_create_icmp(type);
-	if (fd < 0) {
-		goto errout;
-	}
-
-	gai = _fast_ping_getaddr(host, SOCK_RAW, icmp_proto);
-	if (gai == NULL) {
-		goto errout;
-	}
-
-	ping_host = malloc(sizeof(*ping_host));
-	if (ping_host == NULL) {
-		goto errout;
-	}
-
-	memset(ping_host, 0, sizeof(*ping_host));
-	strncpy(ping_host->host, host, PING_MAX_HOSTLEN);
-	ping_host->fd = fd;
-	ping_host->timeout = timeout;
-	ping_host->count = count;
-	ping_host->type = type;
-	ping_host->userptr = userptr;
-	atomic_set(&ping_host->ref, 0);
-	ping_host->sid = atomic_inc_return(&ping_sid);
-	if (ping_callback) {
-		ping_host->ping_callback = ping_callback;
-	} else {
-		ping_host->ping_callback = fast_ping_print_result;
-	}
-	ping_host->interval = (timeout > interval) ? timeout : interval;
-	ping_host->addr_len = gai->ai_addrlen;
-	if (gai->ai_addrlen > sizeof(struct sockaddr_in6)) {
-		goto errout;
-	}
-	memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen);
-
-	tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid);
-	if (_fast_ping_sendping(ping_host) != 0) {
-		goto errout1;
-	}
-
-	hostkey = hash_string(ping_host->host);
-	addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0);
-	addrkey = jhash(&ping_host->sid, sizeof(ping_host->sid), addrkey);
-	pthread_mutex_lock(&ping.map_lock);
-	_fast_ping_host_get(ping_host);
-	hash_add(ping.hostmap, &ping_host->host_node, hostkey);
-	hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
-	pthread_mutex_unlock(&ping.map_lock);
-
-	freeaddrinfo(gai);
-
-
-	return ping_host;
+    struct ping_host_struct *ping_host = NULL;
+    struct addrinfo *gai = NULL;
+    int domain = -1;
+    int icmp_proto = 0;
+    uint32_t hostkey;
+    uint32_t addrkey;
+    char ip_str[PING_MAX_HOSTLEN];
+    char port_str[MAX_IP_LEN];
+    char *service = NULL;
+    int port = -1;
+    FAST_PING_TYPE type;
+    int socktype = 0;
+
+    if (parse_ip(host, ip_str, &port) != 0) {
+        goto errout;
+    }
+
+    if (port > 0) {
+        icmp_proto = 0;
+        socktype = SOCK_STREAM;
+        snprintf(port_str, MAX_IP_LEN, "%d", port);
+        service = port_str;
+        type = FAST_PING_TCP;
+
+        gai = _fast_ping_getaddr(ip_str, service, socktype, icmp_proto);
+        if (gai == NULL) {
+            goto errout;
+        }
+    } else {
+        socktype = SOCK_RAW;
+        domain = _fast_ping_getdomain(ip_str);
+        if (domain < 0) {
+            return NULL;
+        }
+
+        switch (domain) {
+        case AF_INET:
+            icmp_proto = IPPROTO_ICMP;
+            type = FAST_PING_ICMP;
+            break;
+        case AF_INET6:
+            icmp_proto = IPPROTO_ICMPV6;
+            type = FAST_PING_ICMP6;
+            break;
+        default:
+            return NULL;
+            break;
+        }
+
+        if (_fast_ping_create_icmp(type) < 0) {
+            goto errout;
+        }
+
+        gai = _fast_ping_getaddr(ip_str, service, socktype, icmp_proto);
+        if (gai == NULL) {
+            goto errout;
+        }
+    }
+
+    ping_host = malloc(sizeof(*ping_host));
+    if (ping_host == NULL) {
+        goto errout;
+    }
+
+    memset(ping_host, 0, sizeof(*ping_host));
+    strncpy(ping_host->host, host, PING_MAX_HOSTLEN);
+    ping_host->fd = -1;
+    ping_host->timeout = timeout;
+    ping_host->count = count;
+    ping_host->type = type;
+    ping_host->userptr = userptr;
+    atomic_set(&ping_host->ref, 0);
+    ping_host->sid = atomic_inc_return(&ping_sid);
+    if (ping_callback) {
+        ping_host->ping_callback = ping_callback;
+    } else {
+        ping_host->ping_callback = fast_ping_print_result;
+    }
+    ping_host->interval = (timeout > interval) ? timeout : interval;
+    ping_host->addr_len = gai->ai_addrlen;
+    ping_host->port = port;
+    ping_host->ss_family = gai->ai_family;
+    if (gai->ai_addrlen > sizeof(struct sockaddr_in6)) {
+        goto errout;
+    }
+    memcpy(&ping_host->addr, gai->ai_addr, gai->ai_addrlen);
+
+    tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid);
+    if (_fast_ping_sendping(ping_host) != 0) {
+        goto errout;
+    }
+
+    hostkey = hash_string(ping_host->host);
+    addrkey = jhash(&ping_host->addr, ping_host->addr_len, 0);
+    addrkey = jhash(&ping_host->sid, sizeof(ping_host->sid), addrkey);
+    pthread_mutex_lock(&ping.map_lock);
+    _fast_ping_host_get(ping_host);
+    hash_add(ping.hostmap, &ping_host->host_node, hostkey);
+    hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
+    pthread_mutex_unlock(&ping.map_lock);
+
+    freeaddrinfo(gai);
+
+    return ping_host;
 errout:
-	if (fd > 0) {
-		close(fd);
-	}
-errout1:
-	if (gai) {
-		freeaddrinfo(gai);
-	}
+    if (gai) {
+        freeaddrinfo(gai);
+    }
 
-	if (ping_host) {
-		free(ping_host);
-	}
+    if (ping_host) {
+        free(ping_host);
+    }
 
-	return NULL;
+    return NULL;
 }
 
 int fast_ping_stop(struct ping_host_struct *ping_host)
 {
-	_fast_ping_host_put(ping_host);
-	return 0;
+    _fast_ping_host_put(ping_host);
+    return 0;
 }
 
 static void tv_sub(struct timeval *out, struct timeval *in)
 {
-	if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
-		--out->tv_sec;
-		out->tv_usec += 1000000;
-	}
-	out->tv_sec -= in->tv_sec;
+    if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
+        --out->tv_sec;
+        out->tv_usec += 1000000;
+    }
+    out->tv_sec -= in->tv_sec;
 }
 
 static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len)
 {
-	int icmp_len;
-	struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
-	struct icmp6_hdr *icmp6 = &packet->icmp6;
-
-	if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) {
-		tlog(TLOG_DEBUG, "icmp6 type faild, %d:%d", icmp6->icmp6_type, ICMP6_ECHO_REPLY);
-		return NULL;
-	}
-
-	icmp_len = data_len;
-	if (icmp_len < 16) {
-		tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
-		return NULL;
-	}
-
-	if (icmp6->icmp6_id != ping.ident) {
-		tlog(TLOG_ERROR, "ident failed, %d:%d", icmp6->icmp6_id, ping.ident);
-		return NULL;
-	}
-
-	return packet;
+    int icmp_len;
+    struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
+    struct icmp6_hdr *icmp6 = &packet->icmp6;
+
+    if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) {
+        tlog(TLOG_DEBUG, "icmp6 type faild, %d:%d", icmp6->icmp6_type, ICMP6_ECHO_REPLY);
+        return NULL;
+    }
+
+    icmp_len = data_len;
+    if (icmp_len < 16) {
+        tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
+        return NULL;
+    }
+
+    if (icmp6->icmp6_id != ping.ident) {
+        tlog(TLOG_ERROR, "ident failed, %d:%d", icmp6->icmp6_id, ping.ident);
+        return NULL;
+    }
+
+    return packet;
 }
 
 static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *ping_host, u_char *packet_data, int data_len)
 {
-	struct ip *ip = (struct ip *)packet_data;
-	struct fast_ping_packet *packet;
-	struct icmp *icmp;
-	int hlen;
-	int icmp_len;
-
-	if (ip->ip_p != IPPROTO_ICMP) {
-		tlog(TLOG_ERROR, "ip type faild, %d:%d", ip->ip_p, IPPROTO_ICMP);
-		return NULL;
-	}
-
-	hlen = ip->ip_hl << 2;
-	packet = (struct fast_ping_packet *)(packet_data + hlen);
-	icmp = &packet->icmp;
-	icmp_len = data_len - hlen;
-
-	if (icmp_len < 16) {
-		tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
-		return NULL;
-	}
-
-	if (icmp->icmp_type != ICMP_ECHOREPLY) {
-		tlog(TLOG_DEBUG, "icmp type faild, %d:%d", icmp->icmp_type, ICMP_ECHOREPLY);
-		return NULL;
-	}
-
-	if (icmp->icmp_id != ping.ident) {
-		tlog(TLOG_ERROR, "ident failed, %d:%d", icmp->icmp_id, ping.ident);
-		return NULL;
-	}
-
-	return packet;
+    struct ip *ip = (struct ip *)packet_data;
+    struct fast_ping_packet *packet;
+    struct icmp *icmp;
+    int hlen;
+    int icmp_len;
+
+    if (ip->ip_p != IPPROTO_ICMP) {
+        tlog(TLOG_ERROR, "ip type faild, %d:%d", ip->ip_p, IPPROTO_ICMP);
+        return NULL;
+    }
+
+    hlen = ip->ip_hl << 2;
+    packet = (struct fast_ping_packet *)(packet_data + hlen);
+    icmp = &packet->icmp;
+    icmp_len = data_len - hlen;
+
+    if (icmp_len < 16) {
+        tlog(TLOG_ERROR, "length is invalid, %d", icmp_len);
+        return NULL;
+    }
+
+    if (icmp->icmp_type != ICMP_ECHOREPLY) {
+        tlog(TLOG_DEBUG, "icmp type faild, %d:%d", icmp->icmp_type, ICMP_ECHOREPLY);
+        return NULL;
+    }
+
+    if (icmp->icmp_id != ping.ident) {
+        tlog(TLOG_ERROR, "ident failed, %d:%d", icmp->icmp_id, ping.ident);
+        return NULL;
+    }
+
+    return packet;
 }
 
 struct fast_ping_packet *_fast_ping_recv_packet(struct ping_host_struct *ping_host, u_char *inpacket, int len, struct timeval *tvrecv)
 {
-	struct fast_ping_packet *packet = NULL;
-
-	if (ping_host->type == FAST_PING_ICMP6) {
-		packet = _fast_ping_icmp6_packet(ping_host, inpacket, len);
-		if (packet == NULL) {
-			goto errout;
-		}
-	} else if (ping_host->type == FAST_PING_ICMP) {
-		packet = _fast_ping_icmp_packet(ping_host, inpacket, len);
-		if (packet == NULL) {
-			goto errout;
-		}
-	} else {
-		tlog(TLOG_ERROR, "ping host type is invalid, %d", ping_host->type);
-		goto errout;
-	}
-
-	return packet;
+    struct fast_ping_packet *packet = NULL;
+
+    if (ping_host->type == FAST_PING_ICMP6) {
+        packet = _fast_ping_icmp6_packet(ping_host, inpacket, len);
+        if (packet == NULL) {
+            goto errout;
+        }
+    } else if (ping_host->type == FAST_PING_ICMP) {
+        packet = _fast_ping_icmp_packet(ping_host, inpacket, len);
+        if (packet == NULL) {
+            goto errout;
+        }
+    } else {
+        tlog(TLOG_ERROR, "ping host type is invalid, %d", ping_host->type);
+        goto errout;
+    }
+
+    return packet;
 errout:
-	return NULL;
+    return NULL;
 }
 
 static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct timeval *now)
 {
-	int len;
-	u_char inpacket[ICMP_INPACKET_SIZE];
-	struct sockaddr_storage from;
-	struct ping_host_struct *recv_ping_host;
-	struct fast_ping_packet *packet = NULL;
-	socklen_t from_len = sizeof(from);
-	uint32_t addrkey;
-	struct timeval tvresult = *now;
-	struct timeval *tvsend = NULL;
-	unsigned int sid;
-	unsigned int seq;
-
-	len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
-	if (len < 0) {
-		tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno));
-		goto errout;
-	}
-
-	packet = _fast_ping_recv_packet(ping_host, inpacket, len, now);
-	if (packet == NULL) {
-		char name[PING_MAX_HOSTLEN];
-		tlog(TLOG_DEBUG, "recv ping packet from %s failed.", gethost_by_addr(name, (struct sockaddr *)&from, from_len));
-		goto errout;
-	}
-
-	addrkey = jhash(&from, from_len, 0);
-	tvsend = &packet->msg.tv;
-	sid = packet->msg.sid;
-	seq = packet->msg.seq;
-	addrkey = jhash(&sid, sizeof(sid), addrkey);
-	pthread_mutex_lock(&ping.map_lock);
-	hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
-	{
-		if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0 && recv_ping_host->sid == sid) {
-			break;
-		}
-	}
-
-	pthread_mutex_unlock(&ping.map_lock);
-
-	if (recv_ping_host == NULL) {
-		return -1;
-	}
-
-	if (recv_ping_host->seq != seq) {
-		tlog(TLOG_ERROR, "seq num mismatch, expect %u, real %u", recv_ping_host->seq, seq);
-		return -1;
-	}
-
-	tv_sub(&tvresult, tvsend);
-	if (recv_ping_host->ping_callback) {
-		recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len,
-									  recv_ping_host->seq, &tvresult, recv_ping_host->userptr);
-	}
-
-	recv_ping_host->send = 0;
-
-	if (recv_ping_host->count == 1) {
-		_fast_ping_host_put(recv_ping_host);
-	}
-
-	return 0;
+    int len;
+    u_char inpacket[ICMP_INPACKET_SIZE];
+    struct sockaddr_storage from;
+    struct ping_host_struct *recv_ping_host;
+    struct fast_ping_packet *packet = NULL;
+    socklen_t from_len = sizeof(from);
+    uint32_t addrkey;
+    struct timeval tvresult = *now;
+    struct timeval *tvsend = NULL;
+    unsigned int sid;
+    unsigned int seq;
+
+    len = recvfrom(ping_host->fd, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len);
+    if (len < 0) {
+        tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno));
+        goto errout;
+    }
+
+    packet = _fast_ping_recv_packet(ping_host, inpacket, len, now);
+    if (packet == NULL) {
+        char name[PING_MAX_HOSTLEN];
+        tlog(TLOG_DEBUG, "recv ping packet from %s failed.", gethost_by_addr(name, (struct sockaddr *)&from, from_len));
+        goto errout;
+    }
+
+    addrkey = jhash(&from, from_len, 0);
+    tvsend = &packet->msg.tv;
+    sid = packet->msg.sid;
+    seq = packet->msg.seq;
+    addrkey = jhash(&sid, sizeof(sid), addrkey);
+    pthread_mutex_lock(&ping.map_lock);
+    hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
+    {
+        if (recv_ping_host->addr_len == from_len && memcmp(&recv_ping_host->addr, &from, from_len) == 0 && recv_ping_host->sid == sid) {
+            break;
+        }
+    }
+
+    pthread_mutex_unlock(&ping.map_lock);
+
+    if (recv_ping_host == NULL) {
+        return -1;
+    }
+
+    if (recv_ping_host->seq != seq) {
+        tlog(TLOG_ERROR, "seq num mismatch, expect %u, real %u", recv_ping_host->seq, seq);
+        return -1;
+    }
+
+    tv_sub(&tvresult, tvsend);
+    if (recv_ping_host->ping_callback) {
+        recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len,
+            recv_ping_host->seq, &tvresult, recv_ping_host->userptr);
+    }
+
+    recv_ping_host->send = 0;
+
+    if (recv_ping_host->count == 1) {
+        _fast_ping_host_put(recv_ping_host);
+    }
+
+    return 0;
 errout:
-	return -1;
+    return -1;
 }
 
-static int _fast_ping_process(struct ping_host_struct *ping_host, struct timeval *now)
+static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epoll_event *event, struct timeval *now)
 {
-	int ret = -1;
-
-	switch (ping_host->type) {
-	case FAST_PING_ICMP6:
-	case FAST_PING_ICMP:
-		ret = _fast_ping_process_icmp(ping_host, now);
-		break;
-	default:
-		break;
-	}
+    struct timeval tvresult = *now;
+    struct timeval *tvsend = &ping_host->last;
+    int connect_error = 0;
+    socklen_t len = sizeof(connect_error);
+
+    if (event->events & EPOLLIN || event->events & EPOLLERR) {
+        if (getsockopt(ping_host->fd, SOL_SOCKET, SO_ERROR, (char *)&connect_error, &len) != 0) {
+            goto errout;
+        }
+        if (connect_error != 0 && connect_error != ECONNREFUSED) {
+            goto errout;
+        }
+    }
+    tv_sub(&tvresult, tvsend);
+    if (ping_host->ping_callback) {
+        ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr, ping_host->addr_len,
+            ping_host->seq, &tvresult, ping_host->userptr);
+    }
+
+    ping_host->send = 0;
+
+    if (ping_host->fd > 0) {
+        close(ping_host->fd);
+        ping_host->fd = -1;
+    }
+
+    if (ping_host->count == 1) {
+        _fast_ping_host_put(ping_host);
+    }
+    return 0;
+errout:
+    if (ping_host->fd > 0) {
+        close(ping_host->fd);
+        ping_host->fd = -1;
+    }
 
-	return ret;
+    return -1;
 }
 
-static void _fast_ping_period_run()
+static int _fast_ping_process(struct ping_host_struct *ping_host, struct epoll_event *event, struct timeval *now)
 {
-	struct ping_host_struct *ping_host;
-	struct hlist_node *tmp;
-	int i = 0;
-	struct timeval now;
-	struct timeval interval;
-	int64_t millisecond;
-	gettimeofday(&now, 0);
-
-	pthread_mutex_lock(&ping.map_lock);
-	hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node)
-	{
-		interval = now;
-		tv_sub(&interval, &ping_host->last);
-		millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
-		if (millisecond >= ping_host->timeout && ping_host->send == 1) {
-			ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, &interval,
-									 ping_host->userptr);
-			ping_host->send = 0;
-		}
-
-		if (millisecond < ping_host->interval) {
-			continue;
-		}
-
-		if (ping_host->count > 0) {
-			if (ping_host->count == 1) {
-				hash_del(&ping_host->host_node);
-				hash_del(&ping_host->addr_node);
-				_fast_ping_host_put_locked(ping_host);
-				continue;
-			}
-			ping_host->count--;
-		}
+    int ret = -1;
+
+    switch (ping_host->type) {
+    case FAST_PING_ICMP6:
+    case FAST_PING_ICMP:
+        ret = _fast_ping_process_icmp(ping_host, now);
+        break;
+    case FAST_PING_TCP:
+        ret = _fast_ping_process_tcp(ping_host, event, now);
+    default:
+        break;
+    }
+
+    return ret;
+}
 
-		_fast_ping_sendping(ping_host);
-	}
-	pthread_mutex_unlock(&ping.map_lock);
+static void _fast_ping_period_run()
+{
+    struct ping_host_struct *ping_host;
+    struct hlist_node *tmp;
+    int i = 0;
+    struct timeval now;
+    struct timeval interval;
+    int64_t millisecond;
+    gettimeofday(&now, 0);
+
+    pthread_mutex_lock(&ping.map_lock);
+    hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node)
+    {
+        interval = now;
+        tv_sub(&interval, &ping_host->last);
+        millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
+        if (millisecond >= ping_host->timeout && ping_host->send == 1) {
+            ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, &interval,
+                ping_host->userptr);
+            ping_host->send = 0;
+        }
+
+        if (millisecond < ping_host->interval) {
+            continue;
+        }
+
+        if (ping_host->count > 0) {
+            if (ping_host->count == 1) {
+                hash_del(&ping_host->host_node);
+                hash_del(&ping_host->addr_node);
+                _fast_ping_host_put_locked(ping_host, 1);
+                continue;
+            }
+            ping_host->count--;
+        }
+
+        _fast_ping_sendping(ping_host);
+    }
+    pthread_mutex_unlock(&ping.map_lock);
 }
 
 static void *_fast_ping_work(void *arg)
 {
-	struct epoll_event events[PING_MAX_EVENTS + 1];
-	int num;
-	int i;
-	struct timeval last = {0};
-	struct timeval now = {0};
-	struct timeval diff = {0};
-	uint millisec = 0;
-
-	while (ping.run) {
-		diff = now;
-		tv_sub(&diff, &last);
-		millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000;
-		if (millisec >= 100) {
-			_fast_ping_period_run();
-			last = now;
-		}
-
-		num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, 100);
-		if (num < 0) {
-			gettimeofday(&now, 0);
-			usleep(100000);
-			continue;
-		}
-
-		if (num == 0) {
-			gettimeofday(&now, 0);
-			continue;
-		}
-
-		gettimeofday(&now, 0);
-		for (i = 0; i < num; i++) {
-			struct epoll_event *event = &events[i];
-			struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr;
-			_fast_ping_process(ping_host, &now);
-		}
-	}
-
-	close(ping.epoll_fd);
-	ping.epoll_fd = -1;
-
-	return NULL;
+    struct epoll_event events[PING_MAX_EVENTS + 1];
+    int num;
+    int i;
+    struct timeval last = { 0 };
+    struct timeval now = { 0 };
+    struct timeval diff = { 0 };
+    uint millisec = 0;
+
+    while (ping.run) {
+        diff = now;
+        tv_sub(&diff, &last);
+        millisec = diff.tv_sec * 1000 + diff.tv_usec / 1000;
+        if (millisec >= 100) {
+            _fast_ping_period_run();
+            last = now;
+        }
+
+        num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, 100);
+        if (num < 0) {
+            gettimeofday(&now, 0);
+            usleep(100000);
+            continue;
+        }
+
+        if (num == 0) {
+            gettimeofday(&now, 0);
+            continue;
+        }
+
+        gettimeofday(&now, 0);
+        for (i = 0; i < num; i++) {
+            struct epoll_event *event = &events[i];
+            struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr;
+            _fast_ping_process(ping_host, event, &now);
+        }
+    }
+
+    close(ping.epoll_fd);
+    ping.epoll_fd = -1;
+
+    return NULL;
 }
 
 int fast_ping_init()
 {
-	pthread_attr_t attr;
-	int epollfd = -1;
-	int ret;
-
-	if (ping.epoll_fd > 0) {
-		return -1;
-	}
-
-	memset(&ping, 0, sizeof(ping));
-	pthread_attr_init(&attr);
-
-	epollfd = epoll_create1(EPOLL_CLOEXEC);
-	if (epollfd < 0) {
-		tlog(TLOG_ERROR, "create epoll failed, %s\n", strerror(errno));
-		goto errout;
-	}
-
-	pthread_mutex_init(&ping.map_lock, 0);
-	pthread_mutex_init(&ping.lock, 0);
-	hash_init(ping.hostmap);
-	hash_init(ping.addrmap);
-	ping.epoll_fd = epollfd;
-	ping.ident = getpid();
-	ping.run = 1;
-	ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
-	if (ret != 0) {
-		tlog(TLOG_ERROR, "create ping work thread failed, %s\n", strerror(errno));
-		goto errout;
-	}
-
-	return 0;
+    pthread_attr_t attr;
+    int epollfd = -1;
+    int ret;
+
+    if (ping.epoll_fd > 0) {
+        return -1;
+    }
+
+    memset(&ping, 0, sizeof(ping));
+    pthread_attr_init(&attr);
+
+    epollfd = epoll_create1(EPOLL_CLOEXEC);
+    if (epollfd < 0) {
+        tlog(TLOG_ERROR, "create epoll failed, %s\n", strerror(errno));
+        goto errout;
+    }
+
+    pthread_mutex_init(&ping.map_lock, 0);
+    pthread_mutex_init(&ping.lock, 0);
+    hash_init(ping.hostmap);
+    hash_init(ping.addrmap);
+    ping.epoll_fd = epollfd;
+    ping.ident = getpid();
+    ping.run = 1;
+    ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
+    if (ret != 0) {
+        tlog(TLOG_ERROR, "create ping work thread failed, %s\n", strerror(errno));
+        goto errout;
+    }
+
+    return 0;
 errout:
-	if (ping.tid > 0) {
-		void *retval = NULL;
-		ping.run = 0;
-		pthread_join(ping.tid, &retval);
-	}
+    if (ping.tid > 0) {
+        void *retval = NULL;
+        ping.run = 0;
+        pthread_join(ping.tid, &retval);
+    }
 
-	if (epollfd) {
-		close(epollfd);
-	}
+    if (epollfd) {
+        close(epollfd);
+    }
 
-	pthread_mutex_destroy(&ping.lock);
-	pthread_mutex_destroy(&ping.map_lock);
+    pthread_mutex_destroy(&ping.lock);
+    pthread_mutex_destroy(&ping.map_lock);
 
-	return -1;
+    return -1;
 }
 
 void fast_ping_exit()
 {
-	if (ping.tid > 0) {
-		void *ret = NULL;
-		ping.run = 0;
-		pthread_join(ping.tid, &ret);
-	}
-
-	if (ping.fd_icmp > 0) {
-		close(ping.fd_icmp);
-		ping.fd_icmp = -1;
-	}
-
-	if (ping.fd_icmp6 > 0) {
-		close(ping.fd_icmp6);
-		ping.fd_icmp6 = -1;
-	}
-
-	pthread_mutex_destroy(&ping.lock);
-	pthread_mutex_destroy(&ping.map_lock);
+    if (ping.tid > 0) {
+        void *ret = NULL;
+        ping.run = 0;
+        pthread_join(ping.tid, &ret);
+    }
+
+    if (ping.fd_icmp > 0) {
+        close(ping.fd_icmp);
+        ping.fd_icmp = -1;
+    }
+
+    if (ping.fd_icmp6 > 0) {
+        close(ping.fd_icmp6);
+        ping.fd_icmp6 = -1;
+    }
+
+    pthread_mutex_destroy(&ping.lock);
+    pthread_mutex_destroy(&ping.map_lock);
 }

+ 1 - 2
smartdns.c

@@ -116,7 +116,7 @@ int smartdns_init()
 	}
 
 	tlog_setlogscreen(1);
-	tlog_setlevel(TLOG_INFO);
+	tlog_setlevel(TLOG_ERROR);
 
 	if (dns_conf_server_num <= 0) {
 		if (smartdns_load_from_resolv() != 0) {
@@ -142,7 +142,6 @@ int smartdns_init()
 		tlog(TLOG_ERROR, "start dns client failed.\n");
 		goto errout;
 	}
-
 	ret = smartdns_add_servers();
 	if (ret != 0) {
 		tlog(TLOG_ERROR, "add servers failed.");

+ 3 - 3
smartdns.conf

@@ -1,6 +1,6 @@
 
-# port
-port 53
+# bind
+bind [::]:53
 
 cache-size 1024
 loglevel info
@@ -11,7 +11,7 @@ server 123.207.137.88
 server 119.29.29.29
 server 223.5.5.5
 server 208.67.222.222:5353
-#server 202.141.178.13:5353
+server 202.141.178.13:5353
 #server 77.88.8.8:53
 #server 202.141.162.123:53
 #server 101.132.183.99:53

+ 13 - 4
util.c

@@ -44,11 +44,13 @@ errout:
 	return NULL;
 }
 
-int parse_ip(char *value, char *ip, int *port)
+int parse_ip(const char *value, char *ip, int *port)
 {
 	int offset = 0;
 	char *colon = NULL;
 
+	colon = strstr(value, ":");
+
 	if (strstr(value, "[")) {
 		/* ipv6 with port */
 		char *bracket_end = strstr(value, "]");
@@ -60,9 +62,11 @@ int parse_ip(char *value, char *ip, int *port)
 		memcpy(ip, value + 1, offset);
 		ip[offset] = 0;
 
-		colon = bracket_end + 1;
-
-	} else if (strstr(value, "::")) {
+		colon = strstr(bracket_end, ":");
+		if (colon) {
+			colon++;
+		}
+	} else if (colon && strstr(colon + 1, ":")) {
 		/* ipv6 without port */
 		strncpy(ip, value, MAX_IP_LEN);
 		colon = NULL;
@@ -77,6 +81,7 @@ int parse_ip(char *value, char *ip, int *port)
 			offset = colon - value;
 			colon++;
 			memcpy(ip, value, offset);
+			ip[offset] = 0;
 		}
 	}
 
@@ -87,5 +92,9 @@ int parse_ip(char *value, char *ip, int *port)
 		*port = PORT_NOT_DEFINED;
 	}
 
+	if (ip[0] == 0) {
+		return -1;
+	}
+
 	return 0;
 }

+ 1 - 1
util.h

@@ -12,6 +12,6 @@ unsigned long get_tick_count();
 
 char *gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len);
 
-int parse_ip(char *value, char *ip, int *port);
+int parse_ip(const char *value, char *ip, int *port);
 
 #endif