From ec83f75582be170dde50347e7fb08afd82f367e7 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Sun, 10 Jun 2018 00:29:07 +0800 Subject: [PATCH] Add TCP ping --- Makefile | 2 +- conf.c | 13 +- conf.h | 2 +- dns_server.c | 143 ++++- fast_ping.c | 1396 ++++++++++++++++++++++++++----------------------- smartdns.c | 3 +- smartdns.conf | 6 +- util.c | 17 +- util.h | 2 +- 9 files changed, 898 insertions(+), 686 deletions(-) diff --git a/Makefile b/Makefile index 681c7ef..072231f 100755 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ CXXFLAGS +=-Iinclude .PHONY: all all: $(BIN) - + $(BIN) : $(OBJS) $(CC) $(OBJS) -o $@ -lpthread diff --git a/conf.c b/conf.c index 229bdfd..a3c4333 100644 --- a/conf.c +++ b/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}, diff --git a/conf.h b/conf.h index d8c6a86..0421ae3 100644 --- a/conf.h +++ b/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; diff --git a/dns_server.c b/dns_server.c index 722c0aa..698cafb 100644 --- a/dns_server.c +++ b/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; - snprintf(port_str, sizeof(port_str), "%d", dns_conf_port); - gai = _dns_server_getaddr(NULL, port_str, SOCK_DGRAM, 0); + 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", 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); } diff --git a/fast_ping.c b/fast_ping.c index 3c0278f..ea5daf3 100755 --- a/fast_ping.c +++ b/fast_ping.c @@ -23,6 +23,7 @@ #include "util.h" #include #include +#include #include #include #include @@ -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; + 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]; + 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; + 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 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; + 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); + 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)); + 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}; + 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; + 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); + /* 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"); - } + 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 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}; + static struct sock_fprog filter = { sizeof insns / sizeof(insns[0]), insns }; - if (once) { - return; - } - once = 1; + 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); + /* 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"); - } + 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; + 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; - } + 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; + 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; + 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; - } + 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; + } - domain = result->ai_family; + domain = result->ai_family; - freeaddrinfo(result); + freeaddrinfo(result); - return domain; + 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_locked(struct ping_host_struct *ping_host, int locked) +{ + 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(struct ping_host_struct *ping_host) { - 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); -} - -static void _fast_ping_host_put_locked(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; + 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); + 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)); + 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; - } + 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; + 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; + 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); + 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)); + 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; - } + 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; + return 0; errout: - return -1; + return -1; +} + +static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host) +{ + 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; + } + } + + event.events = EPOLLIN | EPOLLOUT; + event.data.ptr = ping_host; + if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) { + goto errout; + } + + if (ping_host->fd > 0) { + close(ping_host->fd); + } + ping_host->fd = fd; + + return 0; + +errout: + if (fd > 0) { + close(fd); + } + return -1; } static int _fast_ping_sendping(struct ping_host_struct *ping_host) { - int ret = -1; + int ret = -1; - 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); - } + 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); + } - ping_host->send = 1; - gettimeofday(&ping_host->last, 0); + ping_host->send = 1; + gettimeofday(&ping_host->last, 0); - if (ret != 0) { - return ret; - } + if (ret != 0) { + return ret; + } - return 0; + return 0; } -static int _fast_ping_create_sock(FAST_PING_TYPE type) +static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type) { - int fd = -1; - struct ping_host_struct *icmp_host = NULL; - struct epoll_event event; - int buffsize = 64 * 1024; - socklen_t optlen = sizeof(buffsize); + 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; - } + 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); + 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; - } + 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; + icmp_host->fd = fd; + icmp_host->type = type; + return fd; errout: - close(fd); - return -1; + close(fd); + return -1; } static int _fast_ping_create_icmp(FAST_PING_TYPE type) { - int fd = 0; - int *set_fd = NULL; + 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; - } + 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; - } + if (*set_fd > 0) { + goto out; + } - fd = _fast_ping_create_sock(type); - if (fd < 0) { - goto errout; - } + fd = _fast_ping_create_icmp_sock(type); + if (fd < 0) { + goto errout; + } - *set_fd = fd; + *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; + 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; - domain = _fast_ping_getdomain(host); - if (domain < 0) { - return NULL; - } + if (parse_ip(host, ip_str, &port) != 0) { + goto errout; + } - 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 (port > 0) { + icmp_proto = 0; + socktype = SOCK_STREAM; + snprintf(port_str, MAX_IP_LEN, "%d", port); + service = port_str; + type = FAST_PING_TCP; - fd = _fast_ping_create_icmp(type); - if (fd < 0) { - goto errout; - } + 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; + } - gai = _fast_ping_getaddr(host, SOCK_RAW, icmp_proto); - if (gai == NULL) { - goto errout; - } + 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; + } - ping_host = malloc(sizeof(*ping_host)); - if (ping_host == NULL) { - goto errout; - } + if (_fast_ping_create_icmp(type) < 0) { + 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); + gai = _fast_ping_getaddr(ip_str, service, socktype, icmp_proto); + if (gai == NULL) { + goto errout; + } + } - tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid); - if (_fast_ping_sendping(ping_host) != 0) { - goto errout1; - } + ping_host = malloc(sizeof(*ping_host)); + if (ping_host == NULL) { + 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); + 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); - freeaddrinfo(gai); + 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); - return ping_host; + 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; + 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; - } + 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; - } + 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; - } + if (icmp6->icmp6_id != ping.ident) { + tlog(TLOG_ERROR, "ident failed, %d:%d", icmp6->icmp6_id, ping.ident); + return NULL; + } - return packet; + 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; + 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; - } + 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; + 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_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_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; - } + if (icmp->icmp_id != ping.ident) { + tlog(TLOG_ERROR, "ident failed, %d:%d", icmp->icmp_id, ping.ident); + return NULL; + } - return packet; + 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; + 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; - } + 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; + 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; + 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; - } + 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; - } + 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; - } - } + 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); + pthread_mutex_unlock(&ping.map_lock); - if (recv_ping_host == NULL) { - return -1; - } + 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; - } + 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); - } + 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; + recv_ping_host->send = 0; - if (recv_ping_host->count == 1) { - _fast_ping_host_put(recv_ping_host); - } + if (recv_ping_host->count == 1) { + _fast_ping_host_put(recv_ping_host); + } - return 0; + 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; + struct timeval tvresult = *now; + struct timeval *tvsend = &ping_host->last; + int connect_error = 0; + socklen_t len = sizeof(connect_error); - switch (ping_host->type) { - case FAST_PING_ICMP6: - case FAST_PING_ICMP: - ret = _fast_ping_process_icmp(ping_host, now); - break; - default: - break; - } + 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); + } - return ret; + 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 -1; +} + +static int _fast_ping_process(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; + case FAST_PING_TCP: + ret = _fast_ping_process_tcp(ping_host, event, now); + default: + break; + } + + return ret; } 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); + 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; - } + 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 (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--; - } + 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); + _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; + 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; - } + 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; - } + 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; - } + 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); - } - } + 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; + close(ping.epoll_fd); + ping.epoll_fd = -1; - return NULL; + return NULL; } int fast_ping_init() { - pthread_attr_t attr; - int epollfd = -1; - int ret; + pthread_attr_t attr; + int epollfd = -1; + int ret; - if (ping.epoll_fd > 0) { - return -1; - } + if (ping.epoll_fd > 0) { + return -1; + } - memset(&ping, 0, sizeof(ping)); - pthread_attr_init(&attr); + 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; - } + 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; - } + 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; + 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.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_icmp > 0) { + close(ping.fd_icmp); + ping.fd_icmp = -1; + } - if (ping.fd_icmp6 > 0) { - close(ping.fd_icmp6); - ping.fd_icmp6 = -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); + pthread_mutex_destroy(&ping.lock); + pthread_mutex_destroy(&ping.map_lock); } \ No newline at end of file diff --git a/smartdns.c b/smartdns.c index ed1caed..61379f9 100755 --- a/smartdns.c +++ b/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."); diff --git a/smartdns.conf b/smartdns.conf index 2c2edb4..07f8926 100644 --- a/smartdns.conf +++ b/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 \ No newline at end of file diff --git a/util.c b/util.c index 2c579e7..c58bcbf 100644 --- a/util.c +++ b/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; } \ No newline at end of file diff --git a/util.h b/util.h index f37578a..1745016 100644 --- a/util.h +++ b/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 \ No newline at end of file