Support TLS query.
This commit is contained in:
@@ -18,8 +18,8 @@ bind [::]:53
|
|||||||
cache-size 512
|
cache-size 512
|
||||||
|
|
||||||
# prefetch domain
|
# prefetch domain
|
||||||
# prefetch-domain [true|false]
|
# prefetch-domain [yes|no]
|
||||||
# prefetch-domain true
|
# prefetch-domain yes
|
||||||
|
|
||||||
# ttl for all resource record
|
# ttl for all resource record
|
||||||
# rr-ttl: ttl for all record
|
# rr-ttl: ttl for all record
|
||||||
@@ -46,6 +46,10 @@ log-level error
|
|||||||
# server-tcp [IP]:[PORT], default port is 53
|
# server-tcp [IP]:[PORT], default port is 53
|
||||||
# server-tcp 8.8.8.8
|
# server-tcp 8.8.8.8
|
||||||
|
|
||||||
|
# remote tls dns server list
|
||||||
|
# server-tls [IP]:[PORT], default port is 853
|
||||||
|
# server-tls 1.1.1.1
|
||||||
|
|
||||||
# specific address to domain
|
# specific address to domain
|
||||||
# address /domain/ip
|
# address /domain/ip
|
||||||
# address /www.example.com/1.2.3.4
|
# address /www.example.com/1.2.3.4
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ CFLAGS +=-Iinclude
|
|||||||
CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
|
CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
|
||||||
CXXFLAGS=-O2 -Wall -std=c++11
|
CXXFLAGS=-O2 -Wall -std=c++11
|
||||||
CXXFLAGS +=-Iinclude
|
CXXFLAGS +=-Iinclude
|
||||||
LDFLAGS += -lpthread
|
LDFLAGS += -lpthread -lssl -lcrypto
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
|
|
||||||
|
|||||||
14
src/conf.c
14
src/conf.c
@@ -47,7 +47,7 @@ int config_server_name(char *value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_server(char *value, dns_server_type_t type)
|
int config_server(char *value, dns_server_type_t type, int default_port)
|
||||||
{
|
{
|
||||||
int index = dns_conf_server_num;
|
int index = dns_conf_server_num;
|
||||||
struct dns_servers *server;
|
struct dns_servers *server;
|
||||||
@@ -66,7 +66,7 @@ int config_server(char *value, dns_server_type_t type)
|
|||||||
|
|
||||||
/* if port is not defined, set port to default 53 */
|
/* if port is not defined, set port to default 53 */
|
||||||
if (port == PORT_NOT_DEFINED) {
|
if (port == PORT_NOT_DEFINED) {
|
||||||
port = DEFAULT_DNS_PORT;
|
port = default_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
server->type = type;
|
server->type = type;
|
||||||
@@ -187,17 +187,17 @@ errout:
|
|||||||
|
|
||||||
int config_server_udp(char *value)
|
int config_server_udp(char *value)
|
||||||
{
|
{
|
||||||
return config_server(value, DNS_SERVER_UDP);
|
return config_server(value, DNS_SERVER_UDP, DEFAULT_DNS_PORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_server_tcp(char *value)
|
int config_server_tcp(char *value)
|
||||||
{
|
{
|
||||||
return config_server(value, DNS_SERVER_TCP);
|
return config_server(value, DNS_SERVER_TCP, DEFAULT_DNS_PORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_server_http(char *value)
|
int config_server_tls(char *value)
|
||||||
{
|
{
|
||||||
return config_server(value, DNS_SERVER_HTTP);
|
return config_server(value, DNS_SERVER_TLS, DEFAULT_DNS_TLS_PORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_cache_size(char *value)
|
int config_cache_size(char *value)
|
||||||
@@ -470,7 +470,7 @@ struct config_item config_item[] = {
|
|||||||
{"server", config_server_udp},
|
{"server", config_server_udp},
|
||||||
{"address", config_address},
|
{"address", config_address},
|
||||||
{"server-tcp", config_server_tcp},
|
{"server-tcp", config_server_tcp},
|
||||||
{"server-http", config_server_http},
|
{"server-tls", config_server_tls},
|
||||||
{"cache-size", config_cache_size},
|
{"cache-size", config_cache_size},
|
||||||
{"prefetch-domain", config_cache_prefetch_domain},
|
{"prefetch-domain", config_cache_prefetch_domain},
|
||||||
{"log-level", config_log_level},
|
{"log-level", config_log_level},
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#define DNS_MAX_IPLEN 64
|
#define DNS_MAX_IPLEN 64
|
||||||
#define DNS_MAX_PATH 1024
|
#define DNS_MAX_PATH 1024
|
||||||
#define DEFAULT_DNS_PORT 53
|
#define DEFAULT_DNS_PORT 53
|
||||||
|
#define DEFAULT_DNS_TLS_PORT 853
|
||||||
#define DNS_MAX_CONF_CNAME_LEN 128
|
#define DNS_MAX_CONF_CNAME_LEN 128
|
||||||
|
|
||||||
struct dns_servers {
|
struct dns_servers {
|
||||||
|
|||||||
433
src/dns_client.c
433
src/dns_client.c
@@ -42,6 +42,8 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
#define DNS_MAX_HOSTNAME 256
|
#define DNS_MAX_HOSTNAME 256
|
||||||
#define DNS_MAX_EVENTS 64
|
#define DNS_MAX_EVENTS 64
|
||||||
@@ -73,6 +75,14 @@ struct dns_server_buff {
|
|||||||
unsigned short len;
|
unsigned short len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum dns_server_status {
|
||||||
|
DNS_SERVER_STATUS_INIT = 0,
|
||||||
|
DNS_SERVER_STATUS_CONNECTING,
|
||||||
|
DNS_SERVER_STATUS_CONNECTIONLESS,
|
||||||
|
DNS_SERVER_STATUS_CONNECTED,
|
||||||
|
DNS_SERVER_STATUS_DISCONNECTED,
|
||||||
|
} dns_server_status;
|
||||||
|
|
||||||
/* dns server information */
|
/* dns server information */
|
||||||
struct dns_server_info {
|
struct dns_server_info {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
@@ -84,6 +94,9 @@ struct dns_server_info {
|
|||||||
|
|
||||||
/* client socket */
|
/* client socket */
|
||||||
int fd;
|
int fd;
|
||||||
|
SSL *ssl;
|
||||||
|
SSL_CTX *ssl_ctx;
|
||||||
|
dns_server_status status;
|
||||||
|
|
||||||
struct dns_server_buff send_buff;
|
struct dns_server_buff send_buff;
|
||||||
struct dns_server_buff recv_buff;
|
struct dns_server_buff recv_buff;
|
||||||
@@ -142,6 +155,7 @@ struct dns_query_struct {
|
|||||||
static struct dns_client client;
|
static struct dns_client client;
|
||||||
static atomic_t dns_client_sid = ATOMIC_INIT(0);
|
static atomic_t dns_client_sid = ATOMIC_INIT(0);
|
||||||
|
|
||||||
|
|
||||||
/* get addr info */
|
/* get addr info */
|
||||||
static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int type, int protocol)
|
static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int type, int protocol)
|
||||||
{
|
{
|
||||||
@@ -214,6 +228,7 @@ int _dns_client_server_add(char *server_ip, struct addrinfo *gai, dns_server_typ
|
|||||||
server_info->ai_addrlen = gai->ai_addrlen;
|
server_info->ai_addrlen = gai->ai_addrlen;
|
||||||
server_info->type = server_type;
|
server_info->type = server_type;
|
||||||
server_info->fd = 0;
|
server_info->fd = 0;
|
||||||
|
server_info->status = DNS_SERVER_STATUS_INIT;
|
||||||
|
|
||||||
if (gai->ai_addrlen > sizeof(server_info->in6)) {
|
if (gai->ai_addrlen > sizeof(server_info->in6)) {
|
||||||
tlog(TLOG_ERROR, "addr len invalid, %d, %zd, %d", gai->ai_addrlen, sizeof(server_info->addr), server_info->ai_family);
|
tlog(TLOG_ERROR, "addr len invalid, %d, %zd, %d", gai->ai_addrlen, sizeof(server_info->addr), server_info->ai_family);
|
||||||
@@ -253,9 +268,22 @@ static void _dns_client_close_socket(struct dns_server_info *server_info)
|
|||||||
if (server_info->fd <= 0) {
|
if (server_info->fd <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server_info->ssl) {
|
||||||
|
SSL_shutdown(server_info->ssl);
|
||||||
|
SSL_free(server_info->ssl);
|
||||||
|
server_info->ssl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server_info->ssl_ctx) {
|
||||||
|
SSL_CTX_free(server_info->ssl_ctx);
|
||||||
|
server_info->ssl_ctx = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
epoll_ctl(client.epoll_fd, EPOLL_CTL_DEL, server_info->fd, NULL);
|
epoll_ctl(client.epoll_fd, EPOLL_CTL_DEL, server_info->fd, NULL);
|
||||||
close(server_info->fd);
|
close(server_info->fd);
|
||||||
server_info->fd = -1;
|
server_info->fd = -1;
|
||||||
|
server_info->status = DNS_SERVER_STATUS_DISCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove all servers information */
|
/* remove all servers information */
|
||||||
@@ -320,10 +348,17 @@ int _dns_client_server_operate(char *server_ip, int port, dns_server_type_t serv
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server_type == DNS_SERVER_UDP) {
|
switch (server_type) {
|
||||||
|
case DNS_SERVER_UDP:
|
||||||
sock_type = SOCK_DGRAM;
|
sock_type = SOCK_DGRAM;
|
||||||
} else {
|
break;
|
||||||
|
case DNS_SERVER_TLS:
|
||||||
|
case DNS_SERVER_TCP:
|
||||||
sock_type = SOCK_STREAM;
|
sock_type = SOCK_STREAM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get addr info */
|
/* get addr info */
|
||||||
@@ -641,6 +676,7 @@ static int _dns_client_create_socket_udp(struct dns_server_info *server_info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
server_info->fd = fd;
|
server_info->fd = fd;
|
||||||
|
server_info->status = DNS_SERVER_STATUS_CONNECTIONLESS;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
errout:
|
errout:
|
||||||
@@ -683,6 +719,7 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
server_info->fd = fd;
|
server_info->fd = fd;
|
||||||
|
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
errout:
|
errout:
|
||||||
@@ -693,12 +730,91 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _DNS_client_create_socket_tls(struct dns_server_info *server_info)
|
||||||
|
{
|
||||||
|
int fd = 0;
|
||||||
|
struct epoll_event event;
|
||||||
|
SSL_CTX *ctx = NULL;
|
||||||
|
SSL *ssl = NULL;
|
||||||
|
|
||||||
|
ctx = SSL_CTX_new(SSLv23_client_method());
|
||||||
|
if (ctx == NULL) {
|
||||||
|
tlog(TLOG_ERROR, "create ssl ctx failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl = SSL_new(ctx);
|
||||||
|
if (ssl == NULL) {
|
||||||
|
tlog(TLOG_ERROR, "new ssl failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = socket(server_info->ai_family, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
tlog(TLOG_ERROR, "create socket failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (set_fd_nonblock(fd, 1) != 0) {
|
||||||
|
tlog(TLOG_ERROR, "set socket non block failed, %s", strerror(errno));
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(fd, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen) != 0) {
|
||||||
|
if (errno != EINPROGRESS) {
|
||||||
|
tlog(TLOG_ERROR, "connect failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SSL_set_fd(ssl, fd) == 0) {
|
||||||
|
tlog(TLOG_ERROR, "ssl set fd failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&event, 0, sizeof(event));
|
||||||
|
event.events = EPOLLIN | EPOLLOUT;
|
||||||
|
event.data.ptr = server_info;
|
||||||
|
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
|
||||||
|
tlog(TLOG_ERROR, "epoll ctl failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_info->fd = fd;
|
||||||
|
server_info->ssl = ssl;
|
||||||
|
server_info->ssl_ctx = ctx;
|
||||||
|
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||||
|
|
||||||
|
tlog(TLOG_DEBUG, "TLS server connecting.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
errout:
|
||||||
|
if (fd > 0) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssl) {
|
||||||
|
SSL_free(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx) {
|
||||||
|
SSL_CTX_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _dns_client_create_socket(struct dns_server_info *server_info)
|
static int _dns_client_create_socket(struct dns_server_info *server_info)
|
||||||
{
|
{
|
||||||
|
time(&server_info->last_send);
|
||||||
|
time(&server_info->last_recv);
|
||||||
|
|
||||||
if (server_info->type == DNS_SERVER_UDP) {
|
if (server_info->type == DNS_SERVER_UDP) {
|
||||||
return _dns_client_create_socket_udp(server_info);
|
return _dns_client_create_socket_udp(server_info);
|
||||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||||
return _DNS_client_create_socket_tcp(server_info);
|
return _DNS_client_create_socket_tcp(server_info);
|
||||||
|
} else if (server_info->type == DNS_SERVER_TLS) {
|
||||||
|
return _DNS_client_create_socket_tls(server_info);
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -741,6 +857,10 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
|||||||
/* when connected */
|
/* when connected */
|
||||||
if (event->events & EPOLLOUT) {
|
if (event->events & EPOLLOUT) {
|
||||||
struct epoll_event event;
|
struct epoll_event event;
|
||||||
|
|
||||||
|
if (server_info->status != DNS_SERVER_STATUS_CONNECTED) {
|
||||||
|
server_info->status = DNS_SERVER_STATUS_DISCONNECTED;
|
||||||
|
}
|
||||||
pthread_mutex_lock(&client.server_list_lock);
|
pthread_mutex_lock(&client.server_list_lock);
|
||||||
if (server_info->send_buff.len > 0) {
|
if (server_info->send_buff.len > 0) {
|
||||||
/* send data in send_buffer */
|
/* send data in send_buffer */
|
||||||
@@ -861,6 +981,279 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _dns_client_socket_send(SSL *ssl, const void *buf, int num)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int ssl_ret = 0;
|
||||||
|
unsigned long ssl_err = 0;
|
||||||
|
|
||||||
|
if (ssl == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = SSL_write(ssl, buf, num);
|
||||||
|
if (ret > 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_ret = SSL_get_error(ssl, ret);
|
||||||
|
switch (ssl_ret) {
|
||||||
|
case SSL_ERROR_NONE:
|
||||||
|
errno = EAGAIN;
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_ZERO_RETURN:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
errno = EAGAIN;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
errno = EAGAIN;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_SSL:
|
||||||
|
ssl_err = ERR_get_error();
|
||||||
|
if (ERR_GET_REASON(ssl_err) == SSL_R_UNINITIALIZED) {
|
||||||
|
errno = EAGAIN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlog(TLOG_ERROR, "SSL write fail error no: %s(%ld)\n", ERR_reason_error_string(ssl_err), ssl_err);
|
||||||
|
errno = EFAULT;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_SYSCALL:
|
||||||
|
tlog(TLOG_ERROR, "SSL syscall failed, %s", strerror(errno));
|
||||||
|
return ret;
|
||||||
|
default:
|
||||||
|
errno = EFAULT;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _dns_client_socket_recv(SSL *ssl, void *buf, int num)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int ssl_ret = 0;
|
||||||
|
unsigned long ssl_err = 0;
|
||||||
|
|
||||||
|
ret = SSL_read(ssl, buf, num);
|
||||||
|
if (ret > 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_ret = SSL_get_error(ssl, ret);
|
||||||
|
switch (ssl_ret) {
|
||||||
|
case SSL_ERROR_NONE:
|
||||||
|
errno = EAGAIN;
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_ZERO_RETURN:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
errno = EAGAIN;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
errno = EAGAIN;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_SSL:
|
||||||
|
ssl_err = ERR_get_error();
|
||||||
|
if (ERR_GET_REASON(ssl_err) == SSL_R_UNINITIALIZED) {
|
||||||
|
errno = EAGAIN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlog(TLOG_ERROR, "SSL read fail error no: %s(%ld)\n", ERR_reason_error_string(ssl_err), ssl_err);
|
||||||
|
errno = EFAULT;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
case SSL_ERROR_SYSCALL:
|
||||||
|
tlog(TLOG_ERROR, "SSL syscall failed, %s", strerror(errno));
|
||||||
|
return ret;
|
||||||
|
default:
|
||||||
|
errno = EFAULT;
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _dns_client_process_tls(struct dns_server_info *server_info, struct epoll_event *event, unsigned long now)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
int ret = -1;
|
||||||
|
unsigned char *inpacket_data = server_info->recv_buff.data;
|
||||||
|
char from_host[DNS_MAX_CNAME_LEN];
|
||||||
|
struct epoll_event fd_event;
|
||||||
|
int ssl_ret;
|
||||||
|
|
||||||
|
if (server_info->status == DNS_SERVER_STATUS_CONNECTING) {
|
||||||
|
ret = SSL_connect(server_info->ssl);
|
||||||
|
if (ret == 0) {
|
||||||
|
goto errout;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
memset(&fd_event, 0, sizeof(fd_event));
|
||||||
|
ssl_ret = SSL_get_error(server_info->ssl, ret);
|
||||||
|
if (ssl_ret == SSL_ERROR_WANT_READ) {
|
||||||
|
fd_event.events = EPOLLIN;
|
||||||
|
} else if (ssl_ret == SSL_ERROR_WANT_WRITE) {
|
||||||
|
fd_event.events = EPOLLOUT;
|
||||||
|
} else {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd_event.data.ptr = server_info;
|
||||||
|
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_MOD, server_info->fd, &fd_event) != 0) {
|
||||||
|
tlog(TLOG_ERROR, "epoll ctl failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tlog(TLOG_DEBUG, "TLS server connected.\n");
|
||||||
|
server_info->status = DNS_SERVER_STATUS_CONNECTED;
|
||||||
|
memset(&fd_event, 0, sizeof(fd_event));
|
||||||
|
fd_event.events = EPOLLIN | EPOLLOUT;
|
||||||
|
fd_event.data.ptr = server_info;
|
||||||
|
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_MOD, server_info->fd, &fd_event) != 0) {
|
||||||
|
tlog(TLOG_ERROR, "epoll ctl failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* when connected */
|
||||||
|
if (event->events & EPOLLOUT) {
|
||||||
|
pthread_mutex_lock(&client.server_list_lock);
|
||||||
|
if (server_info->send_buff.len > 0) {
|
||||||
|
/* send data in send_buffer */
|
||||||
|
len = _dns_client_socket_send(server_info->ssl, server_info->send_buff.data, server_info->send_buff.len);
|
||||||
|
if (len < 0) {
|
||||||
|
pthread_mutex_unlock(&client.server_list_lock);
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
server_info->send_buff.len -= len;
|
||||||
|
if (server_info->send_buff.len > 0) {
|
||||||
|
memmove(server_info->send_buff.data, server_info->send_buff.data + len, server_info->send_buff.len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&client.server_list_lock);
|
||||||
|
|
||||||
|
/* still remain data, retry */
|
||||||
|
if (server_info->send_buff.len > 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear epllout event */
|
||||||
|
memset(&fd_event, 0, sizeof(fd_event));
|
||||||
|
fd_event.events = EPOLLIN;
|
||||||
|
fd_event.data.ptr = server_info;
|
||||||
|
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_MOD, server_info->fd, &fd_event) != 0) {
|
||||||
|
tlog(TLOG_ERROR, "epoll ctl failed.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
pthread_mutex_lock(&client.server_list_lock);
|
||||||
|
server_info->recv_buff.len = 0;
|
||||||
|
server_info->send_buff.len = 0;
|
||||||
|
_dns_client_close_socket(server_info);
|
||||||
|
pthread_mutex_unlock(&client.server_list_lock);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _dns_client_process(struct dns_server_info *server_info, struct epoll_event *event, unsigned long now)
|
static int _dns_client_process(struct dns_server_info *server_info, struct epoll_event *event, unsigned long now)
|
||||||
{
|
{
|
||||||
if (server_info->type == DNS_SERVER_UDP) {
|
if (server_info->type == DNS_SERVER_UDP) {
|
||||||
@@ -869,6 +1262,9 @@ static int _dns_client_process(struct dns_server_info *server_info, struct epoll
|
|||||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||||
/* receive from tcp */
|
/* receive from tcp */
|
||||||
return _dns_client_process_tcp(server_info, event, now);
|
return _dns_client_process_tcp(server_info, event, now);
|
||||||
|
} else if (server_info->type == DNS_SERVER_TLS) {
|
||||||
|
/* recive from tls */
|
||||||
|
return _dns_client_process_tls(server_info, event, now);
|
||||||
} else {
|
} else {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -981,6 +1377,34 @@ static int _dns_client_send_tcp(struct dns_server_info *server_info, void *packe
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _dns_client_send_tls(struct dns_server_info *server_info, void *packet, unsigned short len)
|
||||||
|
{
|
||||||
|
int send_len = 0;
|
||||||
|
unsigned char inpacket_data[DNS_IN_PACKSIZE];
|
||||||
|
unsigned char *inpacket = inpacket_data;
|
||||||
|
|
||||||
|
/* TCP query format
|
||||||
|
* | len (short) | dns query data |
|
||||||
|
*/
|
||||||
|
*((unsigned short *)(inpacket)) = htons(len);
|
||||||
|
memcpy(inpacket + 2, packet, len);
|
||||||
|
len += 2;
|
||||||
|
|
||||||
|
send_len = _dns_client_socket_send(server_info->ssl, inpacket, len);
|
||||||
|
if (send_len < 0) {
|
||||||
|
if (errno == EAGAIN || server_info->ssl == NULL) {
|
||||||
|
/* save data to buffer, and retry when EPOLLOUT is available */
|
||||||
|
return _dns_client_send_data_to_buffer(server_info, inpacket, len);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if (send_len < len) {
|
||||||
|
/* save remain data to buffer, and retry when EPOLLOUT is available */
|
||||||
|
return _dns_client_send_data_to_buffer(server_info, inpacket + send_len, len - send_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, int len)
|
static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, int len)
|
||||||
{
|
{
|
||||||
struct dns_server_info *server_info, *tmp;
|
struct dns_server_info *server_info, *tmp;
|
||||||
@@ -1012,6 +1436,11 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
|||||||
ret = _dns_client_send_tcp(server_info, packet, len);
|
ret = _dns_client_send_tcp(server_info, packet, len);
|
||||||
send_err = errno;
|
send_err = errno;
|
||||||
break;
|
break;
|
||||||
|
case DNS_SERVER_TLS:
|
||||||
|
/* tls query */
|
||||||
|
ret = _dns_client_send_tls(server_info, packet, len);
|
||||||
|
send_err = errno;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* unsupport query type */
|
/* unsupport query type */
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
DNS_SERVER_UDP,
|
DNS_SERVER_UDP,
|
||||||
DNS_SERVER_TCP,
|
DNS_SERVER_TCP,
|
||||||
DNS_SERVER_HTTP,
|
DNS_SERVER_TLS,
|
||||||
DNS_SERVER_TYPE_END,
|
DNS_SERVER_TYPE_END,
|
||||||
} dns_server_type_t;
|
} dns_server_type_t;
|
||||||
|
|
||||||
|
|||||||
@@ -1332,7 +1332,8 @@ int dns_server_socket(void)
|
|||||||
|
|
||||||
fd = socket(gai->ai_family, gai->ai_socktype, gai->ai_protocol);
|
fd = socket(gai->ai_family, gai->ai_socktype, gai->ai_protocol);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
tlog(TLOG_ERROR, "create socket failed.\n");
|
tlog(TLOG_ERROR, "create socket failed, family = %d, type = %d, proto = %d, %s\n",
|
||||||
|
gai->ai_family, gai->ai_socktype, gai->ai_protocol, strerror(errno));
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
#define RESOLVE_FILE "/etc/resolv.conf"
|
#define RESOLVE_FILE "/etc/resolv.conf"
|
||||||
#define MAX_LINE_LEN 1024
|
#define MAX_LINE_LEN 1024
|
||||||
@@ -175,6 +177,23 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int smartdns_init_ssl(void)
|
||||||
|
{
|
||||||
|
SSL_load_error_strings();
|
||||||
|
SSL_library_init();
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int smartdns_destroy_ssl(void)
|
||||||
|
{
|
||||||
|
ERR_free_strings();
|
||||||
|
EVP_cleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int smartdns_init(void)
|
int smartdns_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@@ -198,9 +217,14 @@ int smartdns_init(void)
|
|||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tlog_setlogscreen(1); */
|
//tlog_setlogscreen(1);
|
||||||
tlog_setlevel(dns_conf_log_level);
|
tlog_setlevel(dns_conf_log_level);
|
||||||
|
|
||||||
|
if (smartdns_init_ssl() != 0) {
|
||||||
|
tlog(TLOG_ERROR, "init ssl failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
if (dns_conf_server_num <= 0) {
|
if (dns_conf_server_num <= 0) {
|
||||||
if (smartdns_load_from_resolv() != 0) {
|
if (smartdns_load_from_resolv() != 0) {
|
||||||
tlog(TLOG_ERROR, "load dns from resolv failed.");
|
tlog(TLOG_ERROR, "load dns from resolv failed.");
|
||||||
@@ -247,6 +271,7 @@ void smartdns_exit(void)
|
|||||||
dns_server_exit();
|
dns_server_exit();
|
||||||
dns_client_exit();
|
dns_client_exit();
|
||||||
fast_ping_exit();
|
fast_ping_exit();
|
||||||
|
smartdns_destroy_ssl();
|
||||||
tlog_exit();
|
tlog_exit();
|
||||||
load_exit();
|
load_exit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* tinylog
|
* tinylog
|
||||||
* Copyright (C) 2018 Ruilin Peng (Nick) <pymumu@gmail.com>
|
* Copyright (C) 2018 Nick Peng <pymumu@gmail.com>
|
||||||
* https://github.com/pymumu/tinylog
|
* https://github.com/pymumu/tinylog
|
||||||
*/
|
*/
|
||||||
|
#ifndef _GNU_SOURCE
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
#endif
|
||||||
#include "tlog.h"
|
#include "tlog.h"
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|||||||
Reference in New Issue
Block a user