From 35f945759dfc3c21689b28cc13f6e9474e38a769 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Tue, 12 Jun 2018 22:08:24 +0800 Subject: [PATCH] fix memory leak --- dns.c | 47 +- dns_client.c | 1174 ++++++++++++++++++++++++++------------------------ dns_server.c | 83 ++-- dns_server.h | 2 + fast_ping.c | 62 ++- smartdns.c | 18 +- util.c | 1 + 7 files changed, 766 insertions(+), 621 deletions(-) diff --git a/dns.c b/dns.c index 6a82fa5..1a9f30f 100644 --- a/dns.c +++ b/dns.c @@ -422,11 +422,16 @@ int dns_add_SOA(struct dns_packet *packet, dns_rr_type type, char *domain, int t ptr += strnlen(soa->mname, DNS_MAX_CNAME_LEN - 1) + 1; strncpy((char *)ptr, soa->rname, DNS_MAX_CNAME_LEN - 1); ptr += strnlen(soa->rname, DNS_MAX_CNAME_LEN - 1) + 1; - dns_write_int(&ptr, soa->serial); - dns_write_int(&ptr, soa->refresh); - dns_write_int(&ptr, soa->retry); - dns_write_int(&ptr, soa->expire); - dns_write_int(&ptr, soa->minimum); + *((unsigned int *)ptr) = soa->serial; + ptr += 4; + *((unsigned int *)ptr) = soa->refresh; + ptr += 4; + *((unsigned int *)ptr) = soa->retry; + ptr += 4; + *((unsigned int *)ptr) = soa->expire; + ptr += 4; + *((unsigned int *)ptr) = soa->minimum; + ptr += 4; len = ptr - data; return dns_add_RAW(packet, type, DNS_T_SOA, domain, ttl, data, len); @@ -452,11 +457,16 @@ int dns_get_SOA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct if (ptr - data + 20 > len) { return -1; } - soa->serial = dns_read_int(&ptr); - soa->refresh = dns_read_int(&ptr); - soa->retry = dns_read_int(&ptr); - soa->expire = dns_read_int(&ptr); - soa->minimum = dns_read_int(&ptr); + soa->serial = *((unsigned int *)ptr); + ptr += 4; + soa->refresh = *((unsigned int *)ptr); + ptr += 4; + soa->retry = *((unsigned int *)ptr); + ptr += 4; + soa->expire = *((unsigned int *)ptr); + ptr += 4; + soa->minimum = *((unsigned int *)ptr); + ptr += 4; return 0; } @@ -580,7 +590,7 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz } len = *ptr; if (len == 0) { - *(output - 1) = 0; + *output = 0; ptr++; break; } @@ -599,6 +609,11 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz continue; } + if (output_len > 0) { + *output = '.'; + output++; + } + if (context->maxsize - (ptr - context->data) < 0) { tlog(TLOG_ERROR, "length is not enouth %d:%d, %p, %p", context->maxsize, ptr - context->data, context->ptr, context->data); return -1; @@ -617,8 +632,6 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz ptr += len; output += len; output_len += len; - *output = '.'; - output++; } if (is_compressed == 0) { @@ -631,6 +644,7 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz static int _dns_encode_domain(struct dns_context *context, char *domain) { int num = 0; + int total_len = 0; unsigned char *ptr_num = context->ptr++; while (_dns_left_len(context) > 1 && *domain != 0) { @@ -646,11 +660,14 @@ static int _dns_encode_domain(struct dns_context *context, char *domain) num++; context->ptr++; domain++; + total_len++; } *ptr_num = num; - *(context->ptr) = 0; - context->ptr++; + if (total_len > 0) { + *(context->ptr) = 0; + context->ptr++; + } return 0; } diff --git a/dns_client.c b/dns_client.c index 38b316e..f5c0431 100644 --- a/dns_client.c +++ b/dns_client.c @@ -50,66 +50,67 @@ #define DNS_HOSTNAME_LEN 128 struct dns_query_server { - int fd; - int type; - char host[DNS_HOSTNAME_LEN]; - struct list_head list; + int fd; + int type; + char host[DNS_HOSTNAME_LEN]; + struct list_head list; }; struct dns_client { - pthread_t tid; - int run; - int epoll_fd; + pthread_t tid; + int run; + int epoll_fd; - pthread_mutex_t server_list_lock; - struct list_head dns_server_list; + pthread_mutex_t server_list_lock; + struct list_head dns_server_list; - pthread_mutex_t dns_request_lock; - struct list_head dns_request_list; - struct list_head dns_request_wait_list; + pthread_mutex_t dns_request_lock; + struct list_head dns_request_list; + struct list_head dns_request_wait_list; - pthread_mutex_t domain_map_lock; - DECLARE_HASHTABLE(domain_map, 6); + pthread_mutex_t domain_map_lock; + DECLARE_HASHTABLE(domain_map, 6); - int udp; + int udp; }; struct dns_server_info { - struct list_head list; - struct ping_host_struct *ping_host; - dns_server_type_t type; - unsigned short ss_family; - socklen_t addr_len; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr addr; - }; + struct list_head list; + struct ping_host_struct *ping_host; + dns_server_type_t type; + unsigned short ss_family; + socklen_t addr_len; + union { + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr addr; + }; }; struct dns_query_replied { - struct hlist_node node; - socklen_t addr_len; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr addr; - }; + struct hlist_node node; + socklen_t addr_len; + union { + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr addr; + }; }; struct dns_query_struct { - atomic_t refcnt; - unsigned short sid; - struct list_head dns_request_list; - struct hlist_node domain_node; - char domain[DNS_MAX_CNAME_LEN]; - int qtype; - atomic_t dns_request_sent; - void *user_ptr; - unsigned long send_tick; - dns_client_callback callback; + atomic_t refcnt; + unsigned short sid; + struct list_head dns_request_list; + struct list_head period_list; + struct hlist_node domain_node; + char domain[DNS_MAX_CNAME_LEN]; + int qtype; + atomic_t dns_request_sent; + void *user_ptr; + unsigned long send_tick; + dns_client_callback callback; - DECLARE_HASHTABLE(replied_map, 4); + DECLARE_HASHTABLE(replied_map, 4); }; static struct dns_client client; @@ -117,728 +118,781 @@ static atomic_t dns_client_sid = ATOMIC_INIT(0); static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int type, int protocol) { - struct addrinfo hints; - struct addrinfo *result = NULL; - int ret = 0; + struct addrinfo hints; + struct addrinfo *result = NULL; + int ret = 0; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = type; - hints.ai_protocol = protocol; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = type; + hints.ai_protocol = protocol; - ret = getaddrinfo(host, port, &hints, &result); - if (ret != 0) { - tlog(TLOG_ERROR, "get addr info failed. %s\n", gai_strerror(errno)); - tlog(TLOG_ERROR, "host = %s, port = %s, type = %d, protocol = %d", host, port, type, protocol); - goto errout; - } + ret = getaddrinfo(host, port, &hints, &result); + if (ret != 0) { + tlog(TLOG_ERROR, "get addr info failed. %s\n", gai_strerror(errno)); + tlog(TLOG_ERROR, "host = %s, port = %s, type = %d, protocol = %d", host, port, type, protocol); + goto errout; + } - return result; + return result; errout: - if (result) { - freeaddrinfo(result); - } - return NULL; + if (result) { + freeaddrinfo(result); + } + return NULL; } int _dns_client_server_exist(struct addrinfo *gai, dns_server_type_t server_type) { - struct dns_server_info *server_info, *tmp; - pthread_mutex_lock(&client.server_list_lock); - list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) - { - if (server_info->addr_len != gai->ai_addrlen || server_info->ss_family != gai->ai_family) { - continue; - } + struct dns_server_info *server_info, *tmp; + pthread_mutex_lock(&client.server_list_lock); + list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) + { + if (server_info->addr_len != gai->ai_addrlen || server_info->ss_family != gai->ai_family) { + continue; + } - if (server_info->type != server_type) { - continue; - } + if (server_info->type != server_type) { + continue; + } - if (memcmp(&server_info->addr, gai->ai_addr, gai->ai_addrlen) != 0) { - continue; - } - pthread_mutex_lock(&client.server_list_lock); - return 0; - } - pthread_mutex_unlock(&client.server_list_lock); - return -1; + if (memcmp(&server_info->addr, gai->ai_addr, gai->ai_addrlen) != 0) { + continue; + } + pthread_mutex_lock(&client.server_list_lock); + return 0; + } + pthread_mutex_unlock(&client.server_list_lock); + return -1; } int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type) { - struct dns_server_info *server_info = NULL; + struct dns_server_info *server_info = NULL; - if (_dns_client_server_exist(gai, server_type) == 0) { - goto errout; - } + if (_dns_client_server_exist(gai, server_type) == 0) { + goto errout; + } - server_info = malloc(sizeof(*server_info)); - if (server_info == NULL) { - goto errout; - } - memset(server_info, 0, sizeof(*server_info)); - server_info->ss_family = gai->ai_family; - server_info->addr_len = gai->ai_addrlen; - server_info->type = server_type; - if (gai->ai_addrlen > sizeof(server_info->in6)) { - tlog(TLOG_ERROR, "addr len invalid, %d, %d, %d", gai->ai_addrlen, sizeof(server_info->addr), server_info->ss_family); - goto errout; - } - memcpy(&server_info->addr, gai->ai_addr, gai->ai_addrlen); + server_info = malloc(sizeof(*server_info)); + if (server_info == NULL) { + goto errout; + } + memset(server_info, 0, sizeof(*server_info)); + server_info->ss_family = gai->ai_family; + server_info->addr_len = gai->ai_addrlen; + server_info->type = server_type; + if (gai->ai_addrlen > sizeof(server_info->in6)) { + tlog(TLOG_ERROR, "addr len invalid, %d, %d, %d", gai->ai_addrlen, sizeof(server_info->addr), server_info->ss_family); + goto errout; + } + memcpy(&server_info->addr, gai->ai_addr, gai->ai_addrlen); - if (fast_ping_start(server_ip, 0, 60000, 1000, NULL, server_info) == NULL) { - goto errout; - } + server_info->ping_host = fast_ping_start(server_ip, 0, 60000, 1000, NULL, server_info); + if (server_info->ping_host == NULL) { + goto errout; + } - pthread_mutex_lock(&client.server_list_lock); - list_add(&server_info->list, &client.dns_server_list); - pthread_mutex_unlock(&client.server_list_lock); - return 0; + pthread_mutex_lock(&client.server_list_lock); + list_add(&server_info->list, &client.dns_server_list); + pthread_mutex_unlock(&client.server_list_lock); + return 0; errout: - if (server_info) { - free(server_info); - } + if (server_info) { + if (server_info->ping_host) { + fast_ping_stop(server_info->ping_host); + } + free(server_info); + } - return -1; + return -1; +} + +void _dns_client_server_remove_all(void) +{ + struct dns_server_info *server_info, *tmp; + pthread_mutex_lock(&client.server_list_lock); + list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) + { + list_del(&server_info->list); + if (fast_ping_stop(server_info->ping_host) != 0) { + tlog(TLOG_ERROR, "stop ping failed.\n"); + } + free(server_info); + } + pthread_mutex_unlock(&client.server_list_lock); } int _dns_client_server_remove(char *server_ip, struct addrinfo *gai, dns_server_type_t server_type) { - struct dns_server_info *server_info, *tmp; - pthread_mutex_lock(&client.server_list_lock); - list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) - { - if (server_info->addr_len != gai->ai_addrlen || server_info->ss_family != gai->ai_family) { - continue; - } + struct dns_server_info *server_info, *tmp; + pthread_mutex_lock(&client.server_list_lock); + list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) + { + if (server_info->addr_len != gai->ai_addrlen || server_info->ss_family != gai->ai_family) { + continue; + } - if (memcmp(&server_info->addr, gai->ai_addr, gai->ai_addrlen) != 0) { - continue; - } - list_del(&server_info->list); - pthread_mutex_unlock(&client.server_list_lock); - if (fast_ping_stop(server_info->ping_host) != 0) { - tlog(TLOG_ERROR, "stop ping failed.\n"); - } - free(server_info); - return 0; - } - pthread_mutex_unlock(&client.server_list_lock); - return -1; + if (memcmp(&server_info->addr, gai->ai_addr, gai->ai_addrlen) != 0) { + continue; + } + list_del(&server_info->list); + pthread_mutex_unlock(&client.server_list_lock); + if (fast_ping_stop(server_info->ping_host) != 0) { + tlog(TLOG_ERROR, "stop ping failed.\n"); + } + free(server_info); + return 0; + } + pthread_mutex_unlock(&client.server_list_lock); + return -1; } int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t server_type, int operate) { - char port_s[8]; - int sock_type; - int ret; - struct addrinfo *gai = NULL; + char port_s[8]; + int sock_type; + int ret; + struct addrinfo *gai = NULL; - if (server_type >= DNS_SERVER_TYPE_END) { - return -1; - } + if (server_type >= DNS_SERVER_TYPE_END) { + return -1; + } - if (server_type == DNS_SERVER_UDP) { - sock_type = SOCK_DGRAM; - } else { - sock_type = SOCK_STREAM; - } + if (server_type == DNS_SERVER_UDP) { + sock_type = SOCK_DGRAM; + } else { + sock_type = SOCK_STREAM; + } - snprintf(port_s, 8, "%d", port); - gai = _dns_client_getaddr(server_ip, port_s, sock_type, 0); - if (gai == NULL) { - tlog(TLOG_ERROR, "get address failed, %s:%d", server_ip, port); - goto errout; - } + snprintf(port_s, 8, "%d", port); + gai = _dns_client_getaddr(server_ip, port_s, sock_type, 0); + if (gai == NULL) { + tlog(TLOG_ERROR, "get address failed, %s:%d", server_ip, port); + goto errout; + } - if (operate == 0) { - ret = _dns_client_server_add(server_ip, gai, server_type); - if (ret != 0) { - goto errout; - } - } else { - ret = _dns_client_server_remove(server_ip, gai, server_type); - if (ret != 0) { - goto errout; - } - } - freeaddrinfo(gai); - return 0; + if (operate == 0) { + ret = _dns_client_server_add(server_ip, gai, server_type); + if (ret != 0) { + goto errout; + } + } else { + ret = _dns_client_server_remove(server_ip, gai, server_type); + if (ret != 0) { + goto errout; + } + } + freeaddrinfo(gai); + return 0; errout: - if (gai) { - freeaddrinfo(gai); - } - return -1; + if (gai) { + freeaddrinfo(gai); + } + return -1; } int dns_add_server(char *server_ip, int port, dns_server_type_t server_type) { - return _dns_client_server_operate(server_ip, port, server_type, 0); + return _dns_client_server_operate(server_ip, port, server_type, 0); } int dns_remove_server(char *server_ip, int port, dns_server_type_t server_type) { - return _dns_client_server_operate(server_ip, port, server_type, 1); + return _dns_client_server_operate(server_ip, port, server_type, 1); } void _dns_client_query_release(struct dns_query_struct *query) { - int refcnt = atomic_dec_return(&query->refcnt); + int refcnt = atomic_dec_return(&query->refcnt); int bucket = 0; struct dns_query_replied *replied_map; struct hlist_node *tmp; - if (refcnt) { - if (refcnt < 0) { - tlog(TLOG_ERROR, "BUG: refcnt is %d", refcnt); - abort(); - } - return; - } + if (refcnt) { + if (refcnt < 0) { + tlog(TLOG_ERROR, "BUG: refcnt is %d", refcnt); + abort(); + } + return; + } - if (query->callback) { - query->callback(query->domain, DNS_QUERY_END, NULL, NULL, 0, query->user_ptr); - } + if (query->callback) { + query->callback(query->domain, DNS_QUERY_END, NULL, NULL, 0, query->user_ptr); + } + + pthread_mutex_lock(&client.domain_map_lock); + list_del_init(&query->dns_request_list); + hash_del(&query->domain_node); + pthread_mutex_unlock(&client.domain_map_lock); hash_for_each_safe(query->replied_map, bucket, tmp, replied_map, node) { hash_del(&replied_map->node); free(replied_map); } - memset(query, 0, sizeof(*query)); - free(query); + memset(query, 0, sizeof(*query)); + free(query); } -void _dns_client_query_remove(struct dns_query_struct *query, int locked) +void _dns_client_query_remove(struct dns_query_struct *query) { - if (locked == 0) { - pthread_mutex_lock(&client.domain_map_lock); - list_del_init(&query->dns_request_list); - hash_del(&query->domain_node); - pthread_mutex_unlock(&client.domain_map_lock); - } else { - list_del_init(&query->dns_request_list); - hash_del(&query->domain_node); - } + pthread_mutex_lock(&client.domain_map_lock); + list_del_init(&query->dns_request_list); + hash_del(&query->domain_node); + pthread_mutex_unlock(&client.domain_map_lock); - _dns_client_query_release(query); + _dns_client_query_release(query); +} + +void _dns_client_query_remove_all(void) +{ + struct dns_query_struct *query, *tmp; + LIST_HEAD(check_list); + + pthread_mutex_lock(&client.domain_map_lock); + list_for_each_entry_safe(query, tmp, &client.dns_request_list, dns_request_list) + { + list_add(&query->period_list, &check_list); + } + pthread_mutex_unlock(&client.domain_map_lock); + + list_for_each_entry_safe(query, tmp, &check_list, period_list) + { + list_del_init(&query->period_list); + _dns_client_query_remove(query); + } + + return; } void _dns_client_query_get(struct dns_query_struct *query) { - atomic_inc(&query->refcnt); + atomic_inc(&query->refcnt); } void _dns_client_period_run() { - struct dns_query_struct *query, *tmp; + struct dns_query_struct *query, *tmp; + LIST_HEAD(check_list); - unsigned long now = get_tick_count(); - pthread_mutex_lock(&client.domain_map_lock); - list_for_each_entry_safe(query, tmp, &client.dns_request_list, dns_request_list) - { - if (now - query->send_tick >= 1000) { - _dns_client_query_remove(query, 1); - } - } - pthread_mutex_unlock(&client.domain_map_lock); - return; + unsigned long now = get_tick_count(); + pthread_mutex_lock(&client.domain_map_lock); + list_for_each_entry_safe(query, tmp, &client.dns_request_list, dns_request_list) + { + if (now - query->send_tick >= 1000) { + list_add(&query->period_list, &check_list); + _dns_client_query_get(query); + } + } + pthread_mutex_unlock(&client.domain_map_lock); + + list_for_each_entry_safe(query, tmp, &check_list, period_list) + { + list_del_init(&query->period_list); + _dns_client_query_remove(query); + _dns_client_query_release(query); + } + return; } static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char *domain) { - struct dns_query_struct *query = NULL; - struct hlist_node *tmp = NULL; - unsigned int key; + struct dns_query_struct *query = NULL; + struct hlist_node *tmp = NULL; + unsigned int key; - key = hash_string(domain); - key = jhash(&sid, sizeof(sid), key); - pthread_mutex_lock(&client.domain_map_lock); - hash_for_each_possible_safe(client.domain_map, query, tmp, domain_node, key) - { - if (strncmp(query->domain, domain, DNS_MAX_CNAME_LEN) != 0) { - continue; - } - break; - } - pthread_mutex_unlock(&client.domain_map_lock); + key = hash_string(domain); + key = jhash(&sid, sizeof(sid), key); + pthread_mutex_lock(&client.domain_map_lock); + hash_for_each_possible_safe(client.domain_map, query, tmp, domain_node, key) + { + if (strncmp(query->domain, domain, DNS_MAX_CNAME_LEN) != 0) { + continue; + } + break; + } + pthread_mutex_unlock(&client.domain_map_lock); - return query; + return query; } int _dns_replied_check_add(struct dns_query_struct *dns_query, struct sockaddr *addr, socklen_t addr_len) { - int key = 0; - struct dns_query_replied *replied_map = NULL; + int key = 0; + struct dns_query_replied *replied_map = NULL; - if (addr_len > sizeof(struct sockaddr_in6)) { + if (addr_len > sizeof(struct sockaddr_in6)) { tlog(TLOG_ERROR, "addr length is invalid."); - return -1; - } + return -1; + } - key = jhash(addr, addr_len, 0); - hash_for_each_possible(dns_query->replied_map, replied_map, node, key) - { - if (memcmp(&replied_map->addr, addr, addr_len) == 0) { - return -1; - } - } + key = jhash(addr, addr_len, 0); + hash_for_each_possible(dns_query->replied_map, replied_map, node, key) + { + if (memcmp(&replied_map->addr, addr, addr_len) == 0) { + return -1; + } + } - replied_map = malloc(sizeof(*replied_map)); - if (replied_map == NULL) { - tlog(TLOG_ERROR, "malloc failed"); - return -1; - } + replied_map = malloc(sizeof(*replied_map)); + if (replied_map == NULL) { + tlog(TLOG_ERROR, "malloc failed"); + return -1; + } - memcpy(&replied_map->addr, addr, addr_len); - hash_add(dns_query->replied_map, &replied_map->node, key); - return 0; + memcpy(&replied_map->addr, addr, addr_len); + hash_add(dns_query->replied_map, &replied_map->node, key); + return 0; } - static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct sockaddr_storage *from, socklen_t from_len) { - int len; - int i; - int qtype; - int qclass; - char domain[DNS_MAX_CNAME_LEN]; - int rr_count; - struct dns_rrs *rrs = NULL; - unsigned char packet_buff[DNS_PACKSIZE]; - struct dns_packet *packet = (struct dns_packet *)packet_buff; - int ret = 0; - struct dns_query_struct *query; - int request_num = 0; + int len; + int i; + int qtype; + int qclass; + char domain[DNS_MAX_CNAME_LEN]; + int rr_count; + struct dns_rrs *rrs = NULL; + unsigned char packet_buff[DNS_PACKSIZE]; + struct dns_packet *packet = (struct dns_packet *)packet_buff; + int ret = 0; + struct dns_query_struct *query; + int request_num = 0; - packet->head.tc = 0; - len = dns_decode(packet, DNS_PACKSIZE, inpacket, inpacket_len); - if (len != 0) { - tlog(TLOG_ERROR, "decode failed, packet len = %d, tc=%d, %d\n", inpacket_len, packet->head.tc, packet->head.id); - return -1; - } + packet->head.tc = 0; + len = dns_decode(packet, DNS_PACKSIZE, inpacket, inpacket_len); + if (len != 0) { + tlog(TLOG_ERROR, "decode failed, packet len = %d, tc=%d, %d\n", inpacket_len, packet->head.tc, packet->head.id); + return -1; + } - if (packet->head.qr != DNS_OP_IQUERY) { - tlog(TLOG_ERROR, "message type error.\n"); - return -1; - } + if (packet->head.qr != DNS_OP_IQUERY) { + tlog(TLOG_ERROR, "message type error.\n"); + return -1; + } - tlog(TLOG_DEBUG, "qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d, tc = %d, rd = %d, ra = %d, rcode = %d\n", packet->head.qdcount, - packet->head.ancount, packet->head.nscount, packet->head.nrcount, inpacket_len, packet->head.id, packet->head.tc, packet->head.rd, packet->head.ra, packet->head.rcode); + tlog(TLOG_DEBUG, "qdcount = %d, ancount = %d, nscount = %d, nrcount = %d, len = %d, id = %d, tc = %d, rd = %d, ra = %d, rcode = %d\n", packet->head.qdcount, + packet->head.ancount, packet->head.nscount, packet->head.nrcount, inpacket_len, packet->head.id, packet->head.tc, packet->head.rd, packet->head.ra, + packet->head.rcode); - rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &rr_count); - for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { - dns_get_domain(rrs, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass); - tlog(TLOG_DEBUG, "domain: %s qtype: %d qclass: %d\n", domain, qtype, qclass); - } + rrs = dns_get_rrs_start(packet, DNS_RRS_QD, &rr_count); + for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { + dns_get_domain(rrs, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass); + tlog(TLOG_DEBUG, "domain: %s qtype: %d qclass: %d\n", domain, qtype, qclass); + } - query = _dns_client_get_request(packet->head.id, domain); - if (query == NULL) { - return 0; - } + query = _dns_client_get_request(packet->head.id, domain); + if (query == NULL) { + return 0; + } if (_dns_replied_check_add(query, (struct sockaddr *)from, from_len) != 0) { return 0; } - request_num = atomic_dec_return(&query->dns_request_sent); - if (request_num < 0) { - tlog(TLOG_ERROR, "send count is invalid, %d", request_num); - return -1; - } + request_num = atomic_dec_return(&query->dns_request_sent); + if (request_num < 0) { + tlog(TLOG_ERROR, "send count is invalid, %d", request_num); + return -1; + } - if (query->callback) { - ret = query->callback(query->domain, DNS_QUERY_RESULT, packet, inpacket, inpacket_len, query->user_ptr); - } + if (query->callback) { + ret = query->callback(query->domain, DNS_QUERY_RESULT, packet, inpacket, inpacket_len, query->user_ptr); + } - if (request_num == 0 || ret) { - _dns_client_query_remove(query, 0); - } + if (request_num == 0 || ret) { + _dns_client_query_remove(query); + } - return ret; + return ret; } static int _dns_client_process(struct dns_query_struct *dns_query, unsigned long now) { - int len; - unsigned char inpacket[DNS_IN_PACKSIZE]; - struct sockaddr_storage from; - socklen_t from_len = sizeof(from); - char from_host[DNS_MAX_CNAME_LEN]; + int len; + unsigned char inpacket[DNS_IN_PACKSIZE]; + struct sockaddr_storage from; + socklen_t from_len = sizeof(from); + char from_host[DNS_MAX_CNAME_LEN]; - len = recvfrom(client.udp, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len); - if (len < 0) { - tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno)); - return -1; - } + len = recvfrom(client.udp, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, (socklen_t *)&from_len); + if (len < 0) { + tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno)); + return -1; + } - tlog(TLOG_DEBUG, "recv from %s", gethost_by_addr(from_host, (struct sockaddr *)&from, from_len)); + tlog(TLOG_DEBUG, "recv from %s", gethost_by_addr(from_host, (struct sockaddr *)&from, from_len)); - if (_dns_client_recv(inpacket, len, &from, from_len) != 0) { - int fd = open("dns.bin", O_CREAT | O_TRUNC | O_RDWR); - write(fd, inpacket, len); - close(fd); - return -1; - } + if (_dns_client_recv(inpacket, len, &from, from_len) != 0) { + int fd = open("dns.bin", O_CREAT | O_TRUNC | O_RDWR); + write(fd, inpacket, len); + close(fd); + return -1; + } - return 0; + return 0; } static void *_dns_client_work(void *arg) { - struct epoll_event events[DNS_MAX_EVENTS + 1]; - int num; - int i; - unsigned long now = { 0 }; - unsigned int sleep = 100; - int sleep_time; - unsigned int expect_time = 0; + struct epoll_event events[DNS_MAX_EVENTS + 1]; + int num; + int i; + unsigned long now = {0}; + unsigned int sleep = 100; + int sleep_time; + unsigned int expect_time = 0; sleep_time = sleep; now = get_tick_count() - sleep; expect_time = now + sleep; - while (client.run) { - now = get_tick_count(); - if (now >= expect_time) { - _dns_client_period_run(); - sleep_time = sleep - (now - expect_time); - if (sleep_time < 0) { - sleep_time = 0; - expect_time = now; - } - expect_time += sleep; - } + while (client.run) { + now = get_tick_count(); + if (now >= expect_time) { + _dns_client_period_run(); + sleep_time = sleep - (now - expect_time); + if (sleep_time < 0) { + sleep_time = 0; + expect_time = now; + } + expect_time += sleep; + } - num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time); - if (num < 0) { - usleep(100000); - continue; - } + num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time); + if (num < 0) { + usleep(100000); + continue; + } - for (i = 0; i < num; i++) { - struct epoll_event *event = &events[i]; - struct dns_query_struct *dns_query = (struct dns_query_struct *)event->data.ptr; - _dns_client_process(dns_query, now); - } - } + for (i = 0; i < num; i++) { + struct epoll_event *event = &events[i]; + struct dns_query_struct *dns_query = (struct dns_query_struct *)event->data.ptr; + _dns_client_process(dns_query, now); + } + } - close(client.epoll_fd); - client.epoll_fd = -1; + close(client.epoll_fd); + client.epoll_fd = -1; - return NULL; + return NULL; } static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len) { - int send_len = 0; - send_len = sendto(client.udp, packet, len, 0, (struct sockaddr *)&server_info->addr, server_info->addr_len); - if (send_len != len) { - return -1; - } + int send_len = 0; + send_len = sendto(client.udp, packet, len, 0, (struct sockaddr *)&server_info->addr, server_info->addr_len); + if (send_len != len) { + return -1; + } - return 0; + return 0; } static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, int len) { - struct dns_server_info *server_info, *tmp; - int ret = 0; - - query->send_tick = get_tick_count(); - pthread_mutex_lock(&client.server_list_lock); - list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) - { - atomic_inc(&query->dns_request_sent); - switch (server_info->type) { - case DNS_SERVER_UDP: - ret = _dns_client_send_udp(server_info, packet, len); - break; - default: - ret = -1; - break; - } + struct dns_server_info *server_info, *tmp; + int ret = 0; - if (ret != 0) { - char server_addr[128]; - tlog(TLOG_ERROR, "send query to %s failed, %s", gethost_by_addr(server_addr, &server_info->addr, server_info->addr_len), strerror(errno)); - atomic_dec(&query->dns_request_sent); - continue; - } - } - pthread_mutex_unlock(&client.server_list_lock); - return 0; + query->send_tick = get_tick_count(); + pthread_mutex_lock(&client.server_list_lock); + list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list) + { + atomic_inc(&query->dns_request_sent); + switch (server_info->type) { + case DNS_SERVER_UDP: + ret = _dns_client_send_udp(server_info, packet, len); + break; + default: + ret = -1; + break; + } + + if (ret != 0) { + char server_addr[128]; + tlog(TLOG_ERROR, "send query to %s failed, %s", gethost_by_addr(server_addr, &server_info->addr, server_info->addr_len), strerror(errno)); + atomic_dec(&query->dns_request_sent); + continue; + } + } + pthread_mutex_unlock(&client.server_list_lock); + return 0; } static int _dns_client_send_query(struct dns_query_struct *query, char *doamin) { - unsigned char packet_buff[DNS_PACKSIZE]; - unsigned char inpacket[DNS_IN_PACKSIZE]; - struct dns_packet *packet = (struct dns_packet *)packet_buff; - int encode_len; + unsigned char packet_buff[DNS_PACKSIZE]; + unsigned char inpacket[DNS_IN_PACKSIZE]; + struct dns_packet *packet = (struct dns_packet *)packet_buff; + int encode_len; - struct dns_head head; - memset(&head, 0, sizeof(head)); - head.id = query->sid; - head.qr = DNS_QR_QUERY; - head.opcode = DNS_OP_QUERY; - head.aa = 0; - head.rd = 1; - head.ra = 0; - head.rcode = 0; + struct dns_head head; + memset(&head, 0, sizeof(head)); + head.id = query->sid; + head.qr = DNS_QR_QUERY; + head.opcode = DNS_OP_QUERY; + head.aa = 0; + head.rd = 1; + head.ra = 0; + head.rcode = 0; - dns_packet_init(packet, DNS_PACKSIZE, &head); - dns_add_domain(packet, doamin, query->qtype, DNS_C_IN); - encode_len = dns_encode(inpacket, DNS_IN_PACKSIZE, packet); - if (encode_len <= 0) { - tlog(TLOG_ERROR, "encode query failed."); - return -1; - } + dns_packet_init(packet, DNS_PACKSIZE, &head); + dns_add_domain(packet, doamin, query->qtype, DNS_C_IN); + encode_len = dns_encode(inpacket, DNS_IN_PACKSIZE, packet); + if (encode_len <= 0) { + tlog(TLOG_ERROR, "encode query failed."); + return -1; + } - return _dns_client_send_packet(query, inpacket, encode_len); + return _dns_client_send_packet(query, inpacket, encode_len); } int dns_client_query(char *domain, int qtype, dns_client_callback callback, void *user_ptr) { - struct dns_query_struct *query = NULL; - int ret = 0; - unsigned int key = 0; + struct dns_query_struct *query = NULL; + int ret = 0; + unsigned int key = 0; - query = malloc(sizeof(*query)); - if (query == NULL) { - goto errout; - } - memset(query, 0, sizeof(*query)); - INIT_HLIST_NODE(&query->domain_node); - INIT_LIST_HEAD(&query->dns_request_list); - atomic_set(&query->refcnt, 0); - atomic_set(&query->dns_request_sent, 0); - hash_init(query->replied_map); - strncpy(query->domain, domain, DNS_MAX_CNAME_LEN); - query->user_ptr = user_ptr; - query->callback = callback; - query->qtype = qtype; - query->send_tick = 0; - query->sid = atomic_inc_return(&dns_client_sid); + query = malloc(sizeof(*query)); + if (query == NULL) { + goto errout; + } + memset(query, 0, sizeof(*query)); + INIT_HLIST_NODE(&query->domain_node); + INIT_LIST_HEAD(&query->dns_request_list); + atomic_set(&query->refcnt, 0); + atomic_set(&query->dns_request_sent, 0); + hash_init(query->replied_map); + strncpy(query->domain, domain, DNS_MAX_CNAME_LEN); + query->user_ptr = user_ptr; + query->callback = callback; + query->qtype = qtype; + query->send_tick = 0; + query->sid = atomic_inc_return(&dns_client_sid); - _dns_client_query_get(query); - key = hash_string(domain); - key = jhash(&query->sid, sizeof(query->sid), key); - pthread_mutex_lock(&client.domain_map_lock); - list_add_tail(&query->dns_request_list, &client.dns_request_list); - hash_add(client.domain_map, &query->domain_node, key); - pthread_mutex_unlock(&client.domain_map_lock); + _dns_client_query_get(query); + key = hash_string(domain); + key = jhash(&query->sid, sizeof(query->sid), key); + pthread_mutex_lock(&client.domain_map_lock); + list_add_tail(&query->dns_request_list, &client.dns_request_list); + hash_add(client.domain_map, &query->domain_node, key); + pthread_mutex_unlock(&client.domain_map_lock); - ret = _dns_client_send_query(query, domain); - if (ret != 0) { - goto errout_del_list; - } + ret = _dns_client_send_query(query, domain); + if (ret != 0) { + goto errout_del_list; + } - tlog(TLOG_INFO, "send request %s, id %d\n", domain, query->sid); + tlog(TLOG_INFO, "send request %s, id %d\n", domain, query->sid); - return 0; + return 0; errout_del_list: - atomic_dec(&query->refcnt); - pthread_mutex_lock(&client.domain_map_lock); - list_del_init(&query->dns_request_list); - hash_del(&query->domain_node); - pthread_mutex_unlock(&client.domain_map_lock); + atomic_dec(&query->refcnt); + pthread_mutex_lock(&client.domain_map_lock); + list_del_init(&query->dns_request_list); + hash_del(&query->domain_node); + pthread_mutex_unlock(&client.domain_map_lock); errout: - if (query) { - tlog(TLOG_ERROR, "release %p", query); - free(query); - } - return -1; + if (query) { + tlog(TLOG_ERROR, "release %p", query); + free(query); + } + return -1; } int dns_client_query_raw(char *domain, int qtype, unsigned char *raw, int raw_len, void *user_ptr) { - return -1; + return -1; } static struct addrinfo *_dns_server_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; - hints.ai_flags = AI_PASSIVE; - if (getaddrinfo(host, port, &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; + hints.ai_flags = AI_PASSIVE; + 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; } int dns_client_start(void) { - struct epoll_event event; - event.events = EPOLLIN; - event.data.fd = client.udp; - if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, client.udp, &event) != 0) { - tlog(TLOG_ERROR, "epoll ctl failed."); - return -1; - } + struct epoll_event event; + memset(&event, 0, sizeof(event)); + event.events = EPOLLIN; + event.data.fd = client.udp; + if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, client.udp, &event) != 0) { + tlog(TLOG_ERROR, "epoll ctl failed."); + return -1; + } - return 0; + return 0; } int dns_client_socket(void) { - int fd = -1; - struct addrinfo *gai = NULL; + int fd = -1; + struct addrinfo *gai = NULL; - gai = _dns_server_getaddr(NULL, "53", SOCK_DGRAM, 0); - if (gai == NULL) { - tlog(TLOG_ERROR, "get address failed.\n"); - goto errout; - } + gai = _dns_server_getaddr(NULL, "53", SOCK_DGRAM, 0); + if (gai == NULL) { + tlog(TLOG_ERROR, "get address failed.\n"); + goto errout; + } - fd = socket(gai->ai_family, gai->ai_socktype, gai->ai_protocol); - if (fd < 0) { - tlog(TLOG_ERROR, "create socket failed.\n"); - goto errout; - } + fd = socket(gai->ai_family, gai->ai_socktype, gai->ai_protocol); + if (fd < 0) { + tlog(TLOG_ERROR, "create socket failed.\n"); + goto errout; + } - client.udp = fd; - freeaddrinfo(gai); + client.udp = fd; + freeaddrinfo(gai); - return fd; + return fd; errout: - if (fd > 0) { - close(fd); - } + if (fd > 0) { + close(fd); + } - if (gai) { - freeaddrinfo(gai); - } - return -1; + if (gai) { + freeaddrinfo(gai); + } + return -1; } void dns_debug(void) { - unsigned char data[1024]; - int len; - char buff[4096]; + unsigned char data[1024]; + int len; + char buff[4096]; - int fd = open("dns.bin", O_RDWR); - if (fd < 0) { - return; - } - len = read(fd, data, 1024); - close(fd); - if (len < 0) { - return; - } + int fd = open("dns.bin", O_RDWR); + if (fd < 0) { + return; + } + len = read(fd, data, 1024); + close(fd); + if (len < 0) { + return; + } - struct dns_packet *packet = (struct dns_packet *)buff; - if (dns_decode(packet, 4096, data, len) != 0) { - tlog(TLOG_ERROR, "decode failed.\n"); - } + struct dns_packet *packet = (struct dns_packet *)buff; + if (dns_decode(packet, 4096, data, len) != 0) { + tlog(TLOG_ERROR, "decode failed.\n"); + } - memset(data, 0, sizeof(data)); - len = dns_encode(data, 1024, packet); - if (len < 0) { - tlog(TLOG_ERROR, "encode failed.\n"); - } + memset(data, 0, sizeof(data)); + len = dns_encode(data, 1024, packet); + if (len < 0) { + tlog(TLOG_ERROR, "encode failed.\n"); + } - fd = open("dns-cmp.bin", O_CREAT | O_TRUNC | O_RDWR); - write(fd, data, len); - close(fd); + fd = open("dns-cmp.bin", O_CREAT | O_TRUNC | O_RDWR); + write(fd, data, len); + close(fd); } int dns_client_init() { - pthread_attr_t attr; - int epollfd = -1; - int ret; - int fd = -1; + pthread_attr_t attr; + int epollfd = -1; + int ret; + int fd = -1; - if (client.epoll_fd > 0) { - return -1; - } + if (client.epoll_fd > 0) { + return -1; + } - memset(&client, 0, sizeof(client)); - pthread_attr_init(&attr); + memset(&client, 0, sizeof(client)); + 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; + } - fd = dns_client_socket(); - if (fd < 0) { - tlog(TLOG_ERROR, "create client socket failed.\n"); - goto errout; - } + fd = dns_client_socket(); + if (fd < 0) { + tlog(TLOG_ERROR, "create client socket failed.\n"); + goto errout; + } - pthread_mutex_init(&client.server_list_lock, 0); - INIT_LIST_HEAD(&client.dns_server_list); + pthread_mutex_init(&client.server_list_lock, 0); + INIT_LIST_HEAD(&client.dns_server_list); - pthread_mutex_init(&client.domain_map_lock, 0); - hash_init(client.domain_map); - INIT_LIST_HEAD(&client.dns_request_wait_list); - INIT_LIST_HEAD(&client.dns_request_list); + pthread_mutex_init(&client.domain_map_lock, 0); + hash_init(client.domain_map); + INIT_LIST_HEAD(&client.dns_request_wait_list); + INIT_LIST_HEAD(&client.dns_request_list); - client.epoll_fd = epollfd; - client.run = 1; - client.udp = fd; - ret = pthread_create(&client.tid, &attr, _dns_client_work, NULL); - if (ret != 0) { - tlog(TLOG_ERROR, "create client work thread failed, %s\n", strerror(errno)); - goto errout; - } + client.epoll_fd = epollfd; + client.run = 1; + client.udp = fd; + ret = pthread_create(&client.tid, &attr, _dns_client_work, NULL); + if (ret != 0) { + tlog(TLOG_ERROR, "create client work thread failed, %s\n", strerror(errno)); + goto errout; + } - if (dns_client_start()) { - tlog(TLOG_ERROR, "start client failed.\n"); - goto errout; - } + if (dns_client_start()) { + tlog(TLOG_ERROR, "start client failed.\n"); + goto errout; + } - return 0; + return 0; errout: - if (client.tid > 0) { - void *retval = NULL; - client.run = 0; - pthread_join(client.tid, &retval); - } + if (client.tid > 0) { + void *retval = NULL; + client.run = 0; + pthread_join(client.tid, &retval); + } - if (client.udp > 0) { - close(client.udp); - client.udp = -1; - } + if (client.udp > 0) { + close(client.udp); + client.udp = -1; + } - if (epollfd) { - close(epollfd); - } + if (epollfd) { + close(epollfd); + } - pthread_mutex_destroy(&client.server_list_lock); - pthread_mutex_destroy(&client.domain_map_lock); + pthread_mutex_destroy(&client.server_list_lock); + pthread_mutex_destroy(&client.domain_map_lock); - return -1; + return -1; } void dns_client_exit() { - if (client.tid > 0) { - void *ret = NULL; - client.run = 0; - pthread_join(client.tid, &ret); - } + if (client.tid > 0) { + void *ret = NULL; + client.run = 0; + pthread_join(client.tid, &ret); + } - if (client.udp > 0) { - close(client.udp); - } + if (client.udp > 0) { + close(client.udp); + } - pthread_mutex_destroy(&client.server_list_lock); - pthread_mutex_destroy(&client.domain_map_lock); -} \ No newline at end of file + _dns_client_server_remove_all(); + _dns_client_query_remove_all(); + + pthread_mutex_destroy(&client.server_list_lock); + pthread_mutex_destroy(&client.domain_map_lock); +} diff --git a/dns_server.c b/dns_server.c index f3e74e6..69e7a9b 100644 --- a/dns_server.c +++ b/dns_server.c @@ -72,6 +72,8 @@ struct dns_ip_address { struct dns_request { atomic_t refcnt; struct list_head list; + struct list_head check_list; + char domain[DNS_MAX_CNAME_LEN]; struct dns_head head; unsigned long send_tick; @@ -268,7 +270,7 @@ int _dns_server_request_complete(struct dns_request *request) return ret; } -void _dns_server_request_release_lock(struct dns_request *request, int locked) +void _dns_server_request_release(struct dns_request *request) { struct dns_ip_address *addr_map; struct hlist_node *tmp; @@ -283,13 +285,9 @@ void _dns_server_request_release_lock(struct dns_request *request, int locked) 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); - } + pthread_mutex_lock(&server.request_list_lock); + list_del(&request->list); + pthread_mutex_unlock(&server.request_list_lock); _dns_server_request_complete(request); hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node) @@ -302,11 +300,6 @@ void _dns_server_request_release_lock(struct dns_request *request, int locked) 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); @@ -451,11 +444,19 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain, _dns_server_request_get(request); dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr); - if (addr[0] == 127) { + tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]); + + if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(request->alias, name, DNS_MAX_CNAME_LEN) != 0) { _dns_server_request_release(request); break; } + if (addr[0] == 0) { + _dns_server_request_release(request); + tlog(TLOG_ERROR, "Ad blocker, domain: %s", domain); + break; + } + if (request->has_ipv4 == 0) { memcpy(request->ipv4_addr, addr, DNS_RR_A_LEN); request->has_ipv4 = 1; @@ -464,13 +465,10 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain, _dns_server_request_release(request); break; } - tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]); sprintf(ip, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); - if (strncmp(name, domain, DNS_MAX_CNAME_LEN) == 0 || strncmp(request->alias, name, DNS_MAX_CNAME_LEN) == 0) { - if (fast_ping_start(ip, 1, 0, 1000, _dns_server_ping_result, request) == NULL) { - _dns_server_request_release(request); - } + if (fast_ping_start(ip, 1, 0, 1000, _dns_server_ping_result, request) == NULL) { + _dns_server_request_release(request); } } break; case DNS_T_AAAA: { @@ -478,6 +476,13 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain, _dns_server_request_get(request); dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr); + tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", name, ttl, addr[0], addr[1], + addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]); + if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(request->alias, name, DNS_MAX_CNAME_LEN) != 0) { + _dns_server_request_release(request); + break; + } + if (request->has_ipv6 == 0) { memcpy(request->ipv6_addr, addr, DNS_RR_AAAA_LEN); request->has_ipv6 = 1; @@ -488,9 +493,6 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain, break; } - 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]); @@ -756,7 +758,7 @@ void _dns_server_tcp_ping_check(struct dns_request *request) _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); + _dns_server_request_release(request); } } break; case DNS_T_AAAA: { @@ -767,7 +769,7 @@ void _dns_server_tcp_ping_check(struct dns_request *request) 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); + _dns_server_request_release(request); } } break; default: @@ -782,16 +784,26 @@ void _dns_server_tcp_ping_check(struct dns_request *request) void _dns_server_period_run() { struct dns_request *request, *tmp; + LIST_HEAD(check_list); + 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); + _dns_server_request_get(request); + list_add_tail(&request->check_list, &check_list); } } pthread_mutex_unlock(&server.request_list_lock); + + list_for_each_entry_safe(request, tmp, &check_list, check_list) + { + _dns_server_tcp_ping_check(request); + list_del_init(&request->check_list); + _dns_server_request_release(request); + } } int dns_server_run(void) @@ -872,6 +884,7 @@ errout: int dns_server_start(void) { struct epoll_event event; + memset(&event, 0, sizeof(event)); event.events = EPOLLIN; event.data.fd = server.fd; if (epoll_ctl(server.epoll_fd, EPOLL_CTL_ADD, server.fd, &event) != 0) { @@ -985,8 +998,16 @@ errout: return -1; } +void dns_server_stop(void) +{ + server.run = 0; +} + void dns_server_exit(void) { + struct dns_request *request, *tmp; + LIST_HEAD(remove_list); + server.run = 0; if (server.fd > 0) { @@ -994,5 +1015,17 @@ void dns_server_exit(void) server.fd = -1; } + pthread_mutex_lock(&server.request_list_lock); + list_for_each_entry_safe(request, tmp, &server.request_list, list) + { + list_add_tail(&request->check_list, &remove_list); + } + pthread_mutex_unlock(&server.request_list_lock); + + list_for_each_entry_safe(request, tmp, &remove_list, check_list) + { + _dns_server_request_release(request); + } + pthread_mutex_destroy(&server.request_list_lock); } diff --git a/dns_server.h b/dns_server.h index c21c6be..48d63e8 100644 --- a/dns_server.h +++ b/dns_server.h @@ -5,6 +5,8 @@ int dns_server_init(void); int dns_server_run(void); +void dns_server_stop(void); + void dns_server_exit(void); #endif diff --git a/fast_ping.c b/fast_ping.c index 9e323b3..07acc24 100755 --- a/fast_ping.c +++ b/fast_ping.c @@ -61,7 +61,6 @@ struct fast_ping_packet { struct ping_host_struct { atomic_t ref; atomic_t notified; - struct hlist_node host_node; struct hlist_node addr_node; struct list_head action_list; FAST_PING_TYPE type; @@ -102,7 +101,6 @@ struct fast_ping_struct { struct ping_host_struct icmp6_host; pthread_mutex_t map_lock; - DECLARE_HASHTABLE(hostmap, 6); DECLARE_HASHTABLE(addrmap, 6); }; @@ -243,7 +241,6 @@ static void _fast_ping_host_put(struct ping_host_struct *ping_host) } pthread_mutex_lock(&ping.map_lock); - hash_del(&ping_host->host_node); hash_del(&ping_host->addr_node); pthread_mutex_unlock(&ping.map_lock); @@ -261,6 +258,7 @@ static void _fast_ping_host_put(struct ping_host_struct *ping_host) tlog(TLOG_DEBUG, "ping %p end", ping_host); + memset(ping_host, 0, sizeof(*ping_host)); free(ping_host); } @@ -276,6 +274,7 @@ static void _fast_ping_host_remove(struct ping_host_struct *ping_host) 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); + return; } return _fast_ping_host_put(ping_host); @@ -380,6 +379,7 @@ static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host) } } + memset(&event, 0, sizeof(event)); event.events = EPOLLIN | EPOLLOUT; event.data.ptr = ping_host; if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) { @@ -456,6 +456,7 @@ static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type) setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&buffsize, optlen); setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&buffsize, optlen); + memset(&event, 0, sizeof(event)); event.events = EPOLLIN; event.data.ptr = icmp_host; if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) { @@ -527,7 +528,6 @@ struct ping_host_struct *fast_ping_start(const char *host, int count, int interv 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]; @@ -613,16 +613,12 @@ struct ping_host_struct *fast_ping_start(const char *host, int count, int interv tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid); - 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); - pthread_mutex_unlock(&ping.map_lock); if (_fast_ping_sendping(ping_host) != 0) { - goto errout1; + goto errout; } freeaddrinfo(gai); @@ -632,10 +628,6 @@ struct ping_host_struct *fast_ping_start(const char *host, int count, int interv pthread_mutex_unlock(&ping.map_lock); return ping_host; -errout1: - pthread_mutex_lock(&ping.map_lock); - hash_del(&ping_host->host_node); - pthread_mutex_unlock(&ping.map_lock); errout: if (gai) { freeaddrinfo(gai); @@ -650,6 +642,8 @@ errout: int fast_ping_stop(struct ping_host_struct *ping_host) { + atomic_inc_return(&ping_host->notified); + _fast_ping_host_remove(ping_host); _fast_ping_host_put(ping_host); return 0; } @@ -875,10 +869,33 @@ static int _fast_ping_process(struct ping_host_struct *ping_host, struct epoll_e return ret; } +static void _fast_ping_remove_all(void) +{ + struct ping_host_struct *ping_host = NULL; + struct ping_host_struct *ping_host_tmp = NULL; + struct hlist_node *tmp = NULL; + int i; + + LIST_HEAD(remove_list); + + pthread_mutex_lock(&ping.map_lock); + hash_for_each_safe(ping.addrmap, i, tmp, ping_host, addr_node) + { + list_add_tail(&ping_host->action_list, &remove_list); + } + pthread_mutex_unlock(&ping.map_lock); + + list_for_each_entry_safe(ping_host, ping_host_tmp, &remove_list, action_list) + { + _fast_ping_host_remove(ping_host); + } +} + static void _fast_ping_period_run() { - struct ping_host_struct *ping_host; - struct hlist_node *tmp; + struct ping_host_struct *ping_host = NULL; + struct ping_host_struct *ping_host_tmp = NULL; + struct hlist_node *tmp = NULL; int i = 0; struct timeval now; struct timeval interval; @@ -894,6 +911,7 @@ static void _fast_ping_period_run() millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000; if (millisecond >= ping_host->timeout && ping_host->send == 1) { list_add_tail(&ping_host->action_list, &action); + _fast_ping_host_get(ping_host); continue; } @@ -902,10 +920,11 @@ static void _fast_ping_period_run() } list_add_tail(&ping_host->action_list, &action); + _fast_ping_host_get(ping_host); } pthread_mutex_unlock(&ping.map_lock); - list_for_each_entry(ping_host, &action, action_list) + list_for_each_entry_safe(ping_host, ping_host_tmp, &action, action_list) { interval = now; tv_sub(&interval, &ping_host->last); @@ -917,18 +936,24 @@ static void _fast_ping_period_run() } if (millisecond < ping_host->interval) { + list_del(&ping_host->action_list); + _fast_ping_host_put(ping_host); continue; } if (ping_host->count > 0) { if (ping_host->count == 1) { _fast_ping_host_remove(ping_host); + list_del(&ping_host->action_list); + _fast_ping_host_put(ping_host); continue; } ping_host->count--; } _fast_ping_sendping(ping_host); + list_del(&ping_host->action_list); + _fast_ping_host_put(ping_host); } } @@ -998,7 +1023,6 @@ int fast_ping_init() 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(); @@ -1045,6 +1069,8 @@ void fast_ping_exit() ping.fd_icmp6 = -1; } + _fast_ping_remove_all(); + 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 61379f9..b2272f8 100755 --- a/smartdns.c +++ b/smartdns.c @@ -161,14 +161,23 @@ int smartdns_run() void smartdns_exit() { - fast_ping_exit(); - dns_client_exit(); dns_server_exit(); + dns_client_exit(); + fast_ping_exit(); tlog_exit(); } void sig_handle(int sig) { + + switch (sig) { + case SIGINT: + dns_server_stop(); + return; + break; + default: + break; + } tlog(TLOG_ERROR, "process exit.\n"); _exit(0); } @@ -177,13 +186,16 @@ int main(int argc, char *argv[]) { int ret; - atexit(smartdns_exit); signal(SIGABRT, sig_handle); + ret = smartdns_init(); if (ret != 0) { goto errout; } + signal(SIGINT, sig_handle); + atexit(smartdns_exit); + return smartdns_run(); errout: diff --git a/util.c b/util.c index c58bcbf..7c130d5 100644 --- a/util.c +++ b/util.c @@ -31,6 +31,7 @@ char *gethost_by_addr(char *host, struct sockaddr *addr, socklen_t addr_len) struct sockaddr_in addr_in4; memset(&addr_in4, 0, sizeof(addr_in4)); memcpy(&addr_in4.sin_addr.s_addr, addr_in6->sin6_addr.s6_addr + 12, sizeof(addr_in4.sin_addr.s_addr)); + inet_ntop(AF_INET, &addr_in4.sin_addr, host, addr_len); } else { inet_ntop(AF_INET6, &addr_in6->sin6_addr, host, addr_len); }