From ab417a33068d41f785d88f65d0a5b18306dca4e9 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Wed, 31 Oct 2018 23:54:01 +0800 Subject: [PATCH] TLS bugfix --- etc/smartdns/smartdns.conf | 3 +- src/dns_client.c | 307 +++++++++++++++++++------------------ 2 files changed, 158 insertions(+), 152 deletions(-) diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index b2d2182..09186f3 100644 --- a/etc/smartdns/smartdns.conf +++ b/etc/smartdns/smartdns.conf @@ -48,7 +48,8 @@ log-level error # remote tls dns server list # server-tls [IP]:[PORT], default port is 853 -# server-tls 1.1.1.1 +#server-tls 8.8.8.8 +#server-tls 1.0.0.1 # specific address to domain # address /domain/ip diff --git a/src/dns_client.c b/src/dns_client.c index c572a46..1c2500e 100644 --- a/src/dns_client.c +++ b/src/dns_client.c @@ -854,6 +854,83 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e unsigned char *inpacket_data = server_info->recv_buff.data; char from_host[DNS_MAX_CNAME_LEN]; + if (event->events & EPOLLIN) { + /* receive from tcp */ + len = recv(server_info->fd, server_info->recv_buff.data + server_info->recv_buff.len, DNS_TCP_BUFFER - server_info->recv_buff.len, 0); + if (len < 0) { + /* no data to recv, try again */ + if (errno == EAGAIN) { + return 0; + } + + /* FOR GFW */ + if (errno == ECONNRESET) { + goto errout; + } + + tlog(TLOG_ERROR, "recv failed, %s, %d\n", strerror(errno), errno); + goto errout; + } + + /* peer server close */ + if (len == 0) { + pthread_mutex_lock(&client.server_list_lock); + _dns_client_close_socket(server_info); + server_info->recv_buff.len = 0; + if (server_info->send_buff.len > 0) { + /* still remain request data, reconnect and send*/ + ret = _dns_client_create_socket(server_info); + } else { + ret = 0; + } + pthread_mutex_unlock(&client.server_list_lock); + tlog(TLOG_DEBUG, "peer close, left = %d", server_info->send_buff.len); + return ret; + } + + time(&server_info->last_recv); + + server_info->recv_buff.len += len; + if (server_info->recv_buff.len < 2) { + /* wait and recv */ + return 0; + } + + while (1) { + /* tcp result format + * | len (short) | dns query result | + */ + inpacket_data = server_info->recv_buff.data; + len = ntohs(*((unsigned short *)(inpacket_data))); + if (len <= 0 || len >= DNS_IN_PACKSIZE) { + /* data len is invalid */ + goto errout; + } + + if (len > server_info->recv_buff.len - 2) { + /* len is not expceded, wait and recv */ + break; + } + + inpacket_data = server_info->recv_buff.data + 2; + tlog(TLOG_DEBUG, "recv tcp from %s, len = %d", gethost_by_addr(from_host, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen), len); + + /* process result */ + if (_dns_client_recv(inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) { + goto errout; + } + len += 2; + server_info->recv_buff.len -= len; + + /* move to next result */ + if (server_info->recv_buff.len > 0) { + memmove(server_info->recv_buff.data, server_info->recv_buff.data + len, server_info->recv_buff.len); + } else { + break; + } + } + } + /* when connected */ if (event->events & EPOLLOUT) { struct epoll_event event; @@ -894,81 +971,6 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e return 0; } - /* receive from tcp */ - len = recv(server_info->fd, server_info->recv_buff.data + server_info->recv_buff.len, DNS_TCP_BUFFER - server_info->recv_buff.len, 0); - if (len < 0) { - /* no data to recv, try again */ - if (errno == EAGAIN) { - return 0; - } - - /* FOR GFW */ - if (errno == ECONNRESET) { - goto errout; - } - - tlog(TLOG_ERROR, "recv failed, %s, %d\n", strerror(errno), errno); - goto errout; - } - - /* peer server close */ - if (len == 0) { - pthread_mutex_lock(&client.server_list_lock); - _dns_client_close_socket(server_info); - server_info->recv_buff.len = 0; - if (server_info->send_buff.len > 0) { - /* still remain request data, reconnect and send*/ - ret = _dns_client_create_socket(server_info); - } else { - ret = 0; - } - pthread_mutex_unlock(&client.server_list_lock); - tlog(TLOG_DEBUG, "peer close, left = %d", server_info->send_buff.len); - return ret; - } - - time(&server_info->last_recv); - - server_info->recv_buff.len += len; - if (server_info->recv_buff.len < 2) { - /* wait and recv */ - return 0; - } - - while (1) { - /* tcp result format - * | len (short) | dns query result | - */ - inpacket_data = server_info->recv_buff.data; - len = ntohs(*((unsigned short *)(inpacket_data))); - if (len <= 0 || len >= DNS_IN_PACKSIZE) { - /* data len is invalid */ - goto errout; - } - - if (len > server_info->recv_buff.len - 2) { - /* len is not expceded, wait and recv */ - break; - } - - inpacket_data = server_info->recv_buff.data + 2; - tlog(TLOG_DEBUG, "recv tcp from %s, len = %d", gethost_by_addr(from_host, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen), len); - - /* process result */ - if (_dns_client_recv(inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) { - goto errout; - } - len += 2; - server_info->recv_buff.len -= len; - - /* move to next result */ - if (server_info->recv_buff.len > 0) { - memmove(server_info->recv_buff.data, server_info->recv_buff.data + len, server_info->recv_buff.len); - } else { - break; - } - } - return 0; errout: @@ -1076,7 +1078,8 @@ static int _dns_client_socket_recv(SSL *ssl, void *buf, int num) ret = -1; break; case SSL_ERROR_SYSCALL: - tlog(TLOG_ERROR, "SSL syscall failed, %s", strerror(errno)); + tlog(TLOG_DEBUG, "SSL syscall failed, %s, ", strerror(errno)); + ret = -1; return ret; default: errno = EFAULT; @@ -1188,6 +1191,83 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e } + if (event->events & EPOLLIN) { + /* receive from tcp */ + len = _dns_client_socket_recv(server_info->ssl, server_info->recv_buff.data + server_info->recv_buff.len, DNS_TCP_BUFFER - server_info->recv_buff.len); + if (len < 0) { + /* no data to recv, try again */ + if (errno == EAGAIN) { + return 0; + } + + /* FOR GFW */ + if (errno == ECONNRESET) { + goto errout; + } + + tlog(TLOG_ERROR, "recv failed, %s, %d\n", strerror(errno), errno); + goto errout; + } + + /* peer server close */ + if (len == 0) { + pthread_mutex_lock(&client.server_list_lock); + _dns_client_close_socket(server_info); + server_info->recv_buff.len = 0; + if (server_info->send_buff.len > 0) { + /* still remain request data, reconnect and send*/ + ret = _dns_client_create_socket(server_info); + } else { + ret = 0; + } + pthread_mutex_unlock(&client.server_list_lock); + tlog(TLOG_DEBUG, "peer close, left = %d", server_info->send_buff.len); + return ret; + } + + time(&server_info->last_recv); + + server_info->recv_buff.len += len; + if (server_info->recv_buff.len < 2) { + /* wait and recv */ + return 0; + } + + while (1) { + /* tcp result format + * | len (short) | dns query result | + */ + inpacket_data = server_info->recv_buff.data; + len = ntohs(*((unsigned short *)(inpacket_data))); + if (len <= 0 || len >= DNS_IN_PACKSIZE) { + /* data len is invalid */ + goto errout; + } + + if (len > server_info->recv_buff.len - 2) { + /* len is not expceded, wait and recv */ + break; + } + + inpacket_data = server_info->recv_buff.data + 2; + tlog(TLOG_DEBUG, "recv tcp from %s, len = %d", gethost_by_addr(from_host, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen), len); + + /* process result */ + if (_dns_client_recv(inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) { + goto errout; + } + len += 2; + server_info->recv_buff.len -= len; + + /* move to next result */ + if (server_info->recv_buff.len > 0) { + memmove(server_info->recv_buff.data, server_info->recv_buff.data + len, server_info->recv_buff.len); + } else { + break; + } + } + } + /* when connected */ if (event->events & EPOLLOUT) { pthread_mutex_lock(&client.server_list_lock); @@ -1223,81 +1303,6 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e return 0; } - /* receive from tcp */ - len = _dns_client_socket_recv(server_info->ssl, server_info->recv_buff.data + server_info->recv_buff.len, DNS_TCP_BUFFER - server_info->recv_buff.len); - if (len < 0) { - /* no data to recv, try again */ - if (errno == EAGAIN) { - return 0; - } - - /* FOR GFW */ - if (errno == ECONNRESET) { - goto errout; - } - - tlog(TLOG_ERROR, "recv failed, %s, %d\n", strerror(errno), errno); - goto errout; - } - - /* peer server close */ - if (len == 0) { - pthread_mutex_lock(&client.server_list_lock); - _dns_client_close_socket(server_info); - server_info->recv_buff.len = 0; - if (server_info->send_buff.len > 0) { - /* still remain request data, reconnect and send*/ - ret = _dns_client_create_socket(server_info); - } else { - ret = 0; - } - pthread_mutex_unlock(&client.server_list_lock); - tlog(TLOG_DEBUG, "peer close, left = %d", server_info->send_buff.len); - return ret; - } - - time(&server_info->last_recv); - - server_info->recv_buff.len += len; - if (server_info->recv_buff.len < 2) { - /* wait and recv */ - return 0; - } - - while (1) { - /* tcp result format - * | len (short) | dns query result | - */ - inpacket_data = server_info->recv_buff.data; - len = ntohs(*((unsigned short *)(inpacket_data))); - if (len <= 0 || len >= DNS_IN_PACKSIZE) { - /* data len is invalid */ - goto errout; - } - - if (len > server_info->recv_buff.len - 2) { - /* len is not expceded, wait and recv */ - break; - } - - inpacket_data = server_info->recv_buff.data + 2; - tlog(TLOG_DEBUG, "recv tcp from %s, len = %d", gethost_by_addr(from_host, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen), len); - - /* process result */ - if (_dns_client_recv(inpacket_data, len, &server_info->addr, server_info->ai_addrlen) != 0) { - goto errout; - } - len += 2; - server_info->recv_buff.len -= len; - - /* move to next result */ - if (server_info->recv_buff.len > 0) { - memmove(server_info->recv_buff.data, server_info->recv_buff.data + len, server_info->recv_buff.len); - } else { - break; - } - } - return 0; errout: