From c0c7b8f811168cbfa657b2809e9ca3d1e545f8b0 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Thu, 31 May 2018 23:37:28 +0800 Subject: [PATCH] update code --- dns_client.c | 200 ++++++------------------------------------ dns_client.h | 10 ++- dns_server.c | 243 ++++++++++++++++++++++++++++++++++++++++++++------- smartdns.c | 1 + 4 files changed, 249 insertions(+), 205 deletions(-) diff --git a/dns_client.c b/dns_client.c index 771c1aa..6a729d7 100644 --- a/dns_client.c +++ b/dns_client.c @@ -97,9 +97,7 @@ struct dns_query_struct { atomic_t dns_request_sent; void *user_ptr; unsigned long send_tick; - atomic_t notified; dns_client_callback callback; - struct dns_result result; }; static struct dns_client client; @@ -270,21 +268,6 @@ 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); } -int _dns_client_query_complete(struct dns_query_struct *query) -{ - int ret = -1; - if (atomic_inc_return(&query->notified) != 1) { - return 0; - } - - tlog(TLOG_DEBUG, "call back result : %s", query->domain); - if (query->callback) { - ret = query->callback(query->domain, &query->result, query->user_ptr); - } - - return ret; -} - void _dns_client_query_release(struct dns_query_struct *query) { int refcnt = atomic_dec_return(&query->refcnt); @@ -296,7 +279,10 @@ void _dns_client_query_release(struct dns_query_struct *query) return; } - _dns_client_query_complete(query); + if (query->callback) { + query->callback(query->domain, DNS_QUERY_END, NULL, NULL, 0, query->user_ptr); + } + memset(query, 0, sizeof(*query)); free(query); } @@ -321,66 +307,6 @@ void _dns_client_query_get(struct dns_query_struct *query) atomic_inc(&query->refcnt); } -void dns_client_ping_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 dns_query_struct *query = userptr; - int may_complete = 0; - if (query == NULL) { - return; - } - - if (result == PING_RESULT_END) { - _dns_client_query_release(query); - return; - } - - unsigned int rtt = tv->tv_sec * 10000 + tv->tv_usec / 100; - - switch (addr->sa_family) { - case AF_INET: { - struct sockaddr_in *addr_in; - addr_in = (struct sockaddr_in *)addr; - if (query->result.ttl_v4 > rtt) { - query->result.ttl_v4 = rtt; - memcpy(query->result.addr_ipv4, &addr_in->sin_addr.s_addr, 4); - } - } break; - case AF_INET6: { - struct sockaddr_in6 *addr_in6; - addr_in6 = (struct sockaddr_in6 *)addr; - if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) { - if (query->result.ttl_v4 > rtt) { - query->result.ttl_v4 = rtt; - memcpy(query->result.addr_ipv4, addr_in6->sin6_addr.s6_addr + 12, 4); - } - } else { - if (query->result.ttl_v6 > rtt) { - query->result.ttl_v6 = rtt; - memcpy(query->result.addr_ipv6, addr_in6->sin6_addr.s6_addr, 16); - } - } - } break; - default: - break; - } - if (result == PING_RESULT_RESPONSE) { - 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); - } - - if (rtt < 100) { - may_complete = 1; - } else if (rtt < (get_tick_count() - query->send_tick) * 10) { - may_complete = 1; - } - - if (may_complete) { - _dns_client_query_complete(query); - } -} - void _dns_client_period_run() { struct dns_query_struct *query, *tmp; @@ -390,7 +316,6 @@ void _dns_client_period_run() list_for_each_entry_safe(query, tmp, &client.dns_request_list, dns_request_list) { if (now - query->send_tick >= 2000) { - _dns_client_query_complete(query); _dns_client_query_remove(query, 1); } } @@ -419,100 +344,20 @@ static struct dns_query_struct *_dns_client_get_request(unsigned short sid, char return query; } -static int _dns_client_process_answer(char *domain, struct dns_packet *packet) -{ - struct dns_query_struct *query; - int ttl; - char name[DNS_MAX_CNAME_LEN]; - char alias[DNS_MAX_CNAME_LEN] = {0}; - char ip[DNS_MAX_CNAME_LEN] = {0}; - int rr_count; - int i = 0; - int j = 0; - struct dns_rrs *rrs = NULL; - int request_num = 0; - - query = _dns_client_get_request(packet->head.id, domain); - if (query == NULL) { - 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; - } - - if (packet->head.rcode != DNS_RC_NOERROR) { - tlog(TLOG_ERROR, "inquery failed, %s, rcode = %d\n", name, packet->head.rcode); - if (request_num == 0) { - _dns_client_query_remove(query, 0); - } - return -1; - } - - for (j = 1; j < DNS_RRS_END; j++) { - rrs = dns_get_rrs_start(packet, j, &rr_count); - for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { - switch (rrs->type) { - case DNS_T_A: { - unsigned char addr[4]; - dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr); - tlog(TLOG_DEBUG, "%s %d : %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(alias, name, DNS_MAX_CNAME_LEN) == 0) { - _dns_client_query_get(query); - if (fast_ping_start(ip, 1, 500, dns_client_ping_result, query) == NULL) { - _dns_client_query_release(query); - } - } - } break; - case DNS_T_AAAA: { - unsigned char addr[16]; - dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr); - 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]); - _dns_client_query_get(query); - if (fast_ping_start(name, 1, 500, dns_client_ping_result, query) == NULL) { - _dns_client_query_release(query); - } - } break; - case DNS_T_NS: { - char cname[128]; - dns_get_CNAME(rrs, name, 128, &ttl, cname, 128); - tlog(TLOG_INFO, "NS: %s %d : %s\n", name, ttl, cname); - } break; - case DNS_T_CNAME: { - char cname[128]; - dns_get_CNAME(rrs, name, 128, &ttl, cname, 128); - tlog(TLOG_DEBUG, "%s %d : %s\n", name, ttl, cname); - strncpy(alias, cname, DNS_MAX_CNAME_LEN); - } break; - default: - break; - } - } - } - - if (request_num == 0) { - _dns_client_query_remove(query, 0); - } - - 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 name[DNS_MAX_CNAME_LEN]; + 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); @@ -531,17 +376,30 @@ static int _dns_client_recv(unsigned char *inpacket, int inpacket_len, struct so 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, name, DNS_MAX_CNAME_LEN, &qtype, &qclass); - tlog(TLOG_DEBUG, "domain: %s qtype: %d qclass: %d\n", name, qtype, qclass); + dns_get_domain(rrs, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass); + tlog(TLOG_DEBUG, "domain: %s qtype: %d qclass: %d\n", domain, qtype, qclass); } - if (_dns_client_process_answer(name, packet) != 0) { - char host[DNS_HOSTNAME_LEN]; - tlog(TLOG_ERROR, "process answer failed, %s from %s", name, gethost_by_addr(host, (struct sockaddr *)from, from_len)); + query = _dns_client_get_request(packet->head.id, domain); + if (query == NULL) { + 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; } - return 0; + 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); + } + + return ret; } static int _dns_client_process(struct dns_query_struct *dns_query, unsigned long now) @@ -696,13 +554,10 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void INIT_HLIST_NODE(&query->domain_node); INIT_LIST_HEAD(&query->dns_request_list); atomic_set(&query->refcnt, 0); - atomic_set(&query->notified, 0); atomic_set(&query->dns_request_sent, 0); strncpy(query->domain, domain, DNS_MAX_CNAME_LEN); query->user_ptr = user_ptr; query->callback = callback; - query->result.ttl_v4 = -1; - query->result.ttl_v6 = -1; query->qtype = qtype; query->sid = atomic_inc_return(&dns_client_sid); @@ -714,6 +569,7 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void 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; diff --git a/dns_client.h b/dns_client.h index efa4223..abb227c 100644 --- a/dns_client.h +++ b/dns_client.h @@ -7,7 +7,7 @@ typedef enum { DNS_SERVER_UDP, DNS_SERVER_TCP, DNS_SERVER_HTTP, - DNS_SERVER_TYPE_END, + DNS_SERVER_TYPE_END, } dns_server_type_t; struct dns_result { @@ -18,9 +18,15 @@ struct dns_result { unsigned char addr_ipv6[16]; }; +typedef enum dns_result_type { + DNS_QUERY_ERR, + DNS_QUERY_RESULT = 1, + DNS_QUERY_END, +} dns_result_type; + int dns_client_init(void); -typedef int (*dns_client_callback)(char *domain, struct dns_result *result, void *user_ptr); +typedef int (*dns_client_callback)(char *domain, dns_result_type rtype, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len, void *user_ptr); int dns_client_query(char *domain, int qtype, dns_client_callback callback, void *user_ptr); diff --git a/dns_server.c b/dns_server.c index 5d721f8..ae98806 100644 --- a/dns_server.c +++ b/dns_server.c @@ -20,6 +20,7 @@ #include "atomic.h" #include "dns.h" #include "dns_client.h" +#include "fast_ping.h" #include "hashtable.h" #include "list.h" #include "tlog.h" @@ -60,6 +61,7 @@ struct dns_request { char domain[DNS_MAX_CNAME_LEN]; char alias[DNS_MAX_CNAME_LEN]; struct dns_head head; + unsigned long send_tick; unsigned short qtype; unsigned short id; unsigned short ss_family; @@ -70,8 +72,15 @@ struct dns_request { struct sockaddr addr; }; + int ttl_v4; unsigned char ipv4_addr[DNS_RR_A_LEN]; + + int ttl_v6; unsigned char ipv6_addr[DNS_RR_AAAA_LEN]; + + atomic_t notified; + + int passthrough; }; static struct dns_server server; @@ -173,6 +182,22 @@ static int _dns_add_rrs(struct dns_packet *packet, struct dns_request *request) return ret; } +static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpacket, int inpacket_len) +{ + int send_len = 0; + unsigned short *id = (unsigned short *)inpacket; + + *id = htons(request->id); + + send_len = sendto(server.fd, inpacket, inpacket_len, 0, &request->addr, request->addr_len); + if (send_len != inpacket_len) { + tlog(TLOG_ERROR, "send failed."); + return -1; + } + + return 0; +} + static int _dns_reply(struct dns_request *request) { unsigned char inpacket[DNS_IN_PACKSIZE]; @@ -181,7 +206,6 @@ static int _dns_reply(struct dns_request *request) struct dns_head head; int ret = 0; int encode_len = 0; - int send_len = 0; memset(&head, 0, sizeof(head)); head.id = request->id; @@ -212,49 +236,202 @@ static int _dns_reply(struct dns_request *request) return -1; } - send_len = sendto(server.fd, inpacket, encode_len, 0, &request->addr, request->addr_len); - if (send_len != encode_len) { - tlog(TLOG_ERROR, "send failed."); + return _dns_reply_inpacket(request, inpacket, encode_len); +} + +int _dns_server_request_complete(struct dns_request *request) +{ + int ret = -1; + if (atomic_inc_return(&request->notified) != 1) { + return 0; + } + + if (request->passthrough) { + return 0; + } + + if (request->qtype == DNS_T_A) { + tlog(TLOG_INFO, "result: %s, %d.%d.%d.%d\n", request->domain, 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, %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x", request->domain, 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); + + return ret; +} + +void _dns_server_request_release(struct dns_request *request) +{ + int refcnt = atomic_dec_return(&request->refcnt); + if (refcnt) { + if (refcnt < 0) { + tlog(TLOG_ERROR, "BUG: refcnt is %d", refcnt); + abort(); + } + return; + } + + _dns_server_request_complete(request); + memset(request, 0, sizeof(*request)); + free(request); +} + +void _dns_server_request_get(struct dns_request *request) +{ + atomic_inc(&request->refcnt); +} + +void _dns_server_ping_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 dns_request *request = userptr; + int may_complete = 0; + if (request == NULL) { + return; + } + + if (result == PING_RESULT_END) { + _dns_server_request_release(request); + return; + } + + unsigned int rtt = tv->tv_sec * 10000 + tv->tv_usec / 100; + + switch (addr->sa_family) { + case AF_INET: { + struct sockaddr_in *addr_in; + addr_in = (struct sockaddr_in *)addr; + if (request->ttl_v4 > rtt) { + request->ttl_v4 = rtt; + memcpy(request->ipv4_addr, &addr_in->sin_addr.s_addr, 4); + } + } break; + case AF_INET6: { + struct sockaddr_in6 *addr_in6; + addr_in6 = (struct sockaddr_in6 *)addr; + if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) { + if (request->ttl_v4 > rtt) { + request->ttl_v4 = rtt; + memcpy(request->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4); + } + } else { + if (request->ttl_v6 > rtt) { + request->ttl_v6 = rtt; + memcpy(request->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16); + } + } + } break; + default: + break; + } + if (result == PING_RESULT_RESPONSE) { + 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); + } + + if (rtt < 100) { + may_complete = 1; + } else if (rtt < (get_tick_count() - request->send_tick) * 10) { + may_complete = 1; + } + + if (may_complete) { + _dns_server_request_complete(request); + } +} + +static int _dns_client_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet) +{ + int ttl; + char name[DNS_MAX_CNAME_LEN]; + char alias[DNS_MAX_CNAME_LEN] = {0}; + char ip[DNS_MAX_CNAME_LEN] = {0}; + int rr_count; + int i = 0; + int j = 0; + struct dns_rrs *rrs = NULL; + + if (packet->head.rcode != DNS_RC_NOERROR) { + tlog(TLOG_ERROR, "inquery failed, %s, rcode = %d\n", name, packet->head.rcode); + return -1; + } + + for (j = 1; j < DNS_RRS_END; j++) { + rrs = dns_get_rrs_start(packet, j, &rr_count); + for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) { + switch (rrs->type) { + case DNS_T_A: { + unsigned char addr[4]; + dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr); + tlog(TLOG_DEBUG, "%s %d : %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(alias, name, DNS_MAX_CNAME_LEN) == 0) { + _dns_server_request_get(request); + if (fast_ping_start(ip, 1, 500, _dns_server_ping_result, request) == NULL) { + _dns_server_request_release(request); + } + } + } break; + case DNS_T_AAAA: { + unsigned char addr[16]; + dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr); + 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]); + _dns_server_request_get(request); + if (fast_ping_start(name, 1, 500, _dns_server_ping_result, request) == NULL) { + _dns_server_request_release(request); + } + } break; + case DNS_T_NS: { + char cname[128]; + dns_get_CNAME(rrs, name, 128, &ttl, cname, 128); + tlog(TLOG_INFO, "NS: %s %d : %s\n", name, ttl, cname); + } break; + case DNS_T_CNAME: { + char cname[128]; + dns_get_CNAME(rrs, name, 128, &ttl, cname, 128); + tlog(TLOG_DEBUG, "%s %d : %s\n", name, ttl, cname); + strncpy(alias, cname, DNS_MAX_CNAME_LEN); + } break; + default: + break; + } + } } return 0; } -static int dns_server_resolve_callback(char *domain, struct dns_result *result, void *user_ptr) +static int dns_server_resolve_callback(char *domain, dns_result_type rtype, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len, + void *user_ptr) { struct dns_request *request = user_ptr; - int refcnt; - - if (user_ptr == NULL) { + if (request == NULL) { return -1; } - refcnt = atomic_dec_return(&request->refcnt); - if (refcnt) { - if (refcnt < 0) { - abort(); + if (rtype == DNS_QUERY_RESULT) { + if (request->passthrough) { + _dns_reply_inpacket(request, inpacket, inpacket_len); + return -1; } + _dns_client_process_answer(request, domain, packet); return 0; + } else if (rtype == DNS_QUERY_ERR) { + tlog(TLOG_ERROR, "request faield, %s", domain); + return -1; + } else { + _dns_server_request_release(request); } - memcpy(request->ipv4_addr, result->addr_ipv4, 4); - strncpy(request->alias, result->alias, DNS_MAX_CNAME_LEN); - memcpy(request->ipv6_addr, result->addr_ipv6, 16); - - if (request->qtype == DNS_T_A) { - tlog(TLOG_INFO, "result: %s, %d.%d.%d.%d\n", domain, 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, %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x", domain, 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); - - memset(request, 0, sizeof(*request)); - free(request); - return 0; } @@ -283,6 +460,9 @@ static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct so } request = malloc(sizeof(*request)); + memset(request, 0, sizeof(*request)); + request->ttl_v4 = -1; + request->ttl_v6 = -1; if (request == NULL) { printf("malloc failed.\n"); goto errout; @@ -319,12 +499,13 @@ static int _dns_server_recv(unsigned char *inpacket, int inpacket_len, struct so break; default: tlog(TLOG_INFO, "unsupport qtype: %d, domain: %s", qtype, request->domain); - return ret; + request->passthrough = 1; break; } tlog(TLOG_INFO, "query server %s from %s, qtype = %d\n", request->domain, gethost_by_addr(name, (struct sockaddr *)from, from_len), qtype); - atomic_set(&request->refcnt, 1); + _dns_server_request_get(request); + request->send_tick = get_tick_count(); dns_client_query(request->domain, qtype, dns_server_resolve_callback, request); return 0; diff --git a/smartdns.c b/smartdns.c index 575f239..2b1bbac 100755 --- a/smartdns.c +++ b/smartdns.c @@ -53,6 +53,7 @@ int smartdns_init() } tlog_setlogscreen(1); + //tlog_setlevel(TLOG_DEBUG); ret = fast_ping_init(); if (ret != 0) {