|
@@ -37,6 +37,8 @@
|
|
|
#include <net/if.h>
|
|
|
#include <netinet/ip.h>
|
|
|
#include <netinet/tcp.h>
|
|
|
+#include <openssl/err.h>
|
|
|
+#include <openssl/ssl.h>
|
|
|
#include <pthread.h>
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
@@ -46,6 +48,10 @@
|
|
|
#include <sys/ioctl.h>
|
|
|
#include <sys/socket.h>
|
|
|
#include <sys/types.h>
|
|
|
+#include <openssl/evp.h>
|
|
|
+#include <openssl/rsa.h>
|
|
|
+#include <openssl/pem.h>
|
|
|
+#include <openssl/x509.h>
|
|
|
|
|
|
#define DNS_MAX_EVENTS 256
|
|
|
#define IPV6_READY_CHECK_TIME 180
|
|
@@ -76,6 +82,8 @@ typedef enum {
|
|
|
DNS_CONN_TYPE_TCP_CLIENT,
|
|
|
DNS_CONN_TYPE_TLS_SERVER,
|
|
|
DNS_CONN_TYPE_TLS_CLIENT,
|
|
|
+ DNS_CONN_TYPE_HTTPS_SERVER,
|
|
|
+ DNS_CONN_TYPE_HTTPS_CLIENT,
|
|
|
} DNS_CONN_TYPE;
|
|
|
|
|
|
typedef enum DNS_CHILD_POST_RESULT {
|
|
@@ -132,6 +140,14 @@ struct dns_server_post_context {
|
|
|
int no_release_parent;
|
|
|
};
|
|
|
|
|
|
+typedef enum dns_server_client_status {
|
|
|
+ DNS_SERVER_CLIENT_STATUS_INIT = 0,
|
|
|
+ DNS_SERVER_CLIENT_STATUS_CONNECTING,
|
|
|
+ DNS_SERVER_CLIENT_STATUS_CONNECTIONLESS,
|
|
|
+ DNS_SERVER_CLIENT_STATUS_CONNECTED,
|
|
|
+ DNS_SERVER_CLIENT_STATUS_DISCONNECTED,
|
|
|
+} dns_server_client_status;
|
|
|
+
|
|
|
struct dns_server_conn_udp {
|
|
|
struct dns_server_conn_head head;
|
|
|
socklen_t addr_len;
|
|
@@ -142,6 +158,11 @@ struct dns_server_conn_tcp_server {
|
|
|
struct dns_server_conn_head head;
|
|
|
};
|
|
|
|
|
|
+struct dns_server_conn_tls_server {
|
|
|
+ struct dns_server_conn_head head;
|
|
|
+ SSL_CTX *ssl_ctx;
|
|
|
+};
|
|
|
+
|
|
|
struct dns_server_conn_tcp_client {
|
|
|
struct dns_server_conn_head head;
|
|
|
struct dns_conn_buf recvbuff;
|
|
@@ -151,6 +172,23 @@ struct dns_server_conn_tcp_client {
|
|
|
|
|
|
socklen_t localaddr_len;
|
|
|
struct sockaddr_storage localaddr;
|
|
|
+
|
|
|
+ dns_server_client_status status;
|
|
|
+};
|
|
|
+
|
|
|
+struct dns_server_conn_tls_client {
|
|
|
+ struct dns_server_conn_head head;
|
|
|
+ struct dns_conn_buf recvbuff;
|
|
|
+ struct dns_conn_buf sndbuff;
|
|
|
+ socklen_t addr_len;
|
|
|
+ struct sockaddr_storage addr;
|
|
|
+
|
|
|
+ socklen_t localaddr_len;
|
|
|
+ struct sockaddr_storage localaddr;
|
|
|
+ dns_server_client_status status;
|
|
|
+
|
|
|
+ SSL *ssl;
|
|
|
+ pthread_mutex_t ssl_lock;
|
|
|
};
|
|
|
|
|
|
/* ip address lists of domain */
|
|
@@ -306,6 +344,7 @@ static int _dns_request_post(struct dns_server_post_context *context);
|
|
|
static int _dns_server_reply_all_pending_list(struct dns_request *request, struct dns_server_post_context *context);
|
|
|
static void *_dns_server_get_dns_rule(struct dns_request *request, enum domain_rule rule);
|
|
|
static const char *_dns_server_get_request_groupname(struct dns_request *request);
|
|
|
+static int _dns_server_tcp_socket_send(struct dns_server_conn_tcp_client *tcp_client, void *data, int data_len);
|
|
|
|
|
|
static void _dns_server_wakeup_thread(void)
|
|
|
{
|
|
@@ -460,7 +499,7 @@ static int _dns_server_is_return_soa(struct dns_request *request)
|
|
|
unsigned int flags = 0;
|
|
|
|
|
|
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_SOA) == 0) {
|
|
|
- /* when both has no rule SOA and force AAAA soa, foce AAAA soa has high priority */
|
|
|
+ /* when both has no rule SOA and force AAAA soa, force AAAA soa has high priority */
|
|
|
if (request->qtype == DNS_T_AAAA && _dns_server_has_bind_flag(request, BIND_FLAG_FORCE_AAAA_SOA) == 0) {
|
|
|
return 1;
|
|
|
}
|
|
@@ -961,6 +1000,21 @@ static void _dns_server_conn_release(struct dns_server_conn_head *conn)
|
|
|
conn->fd = -1;
|
|
|
}
|
|
|
|
|
|
+ if (conn->type == DNS_CONN_TYPE_TLS_CLIENT || conn->type == DNS_CONN_TYPE_HTTPS_CLIENT) {
|
|
|
+ struct dns_server_conn_tls_client *tls_client = (struct dns_server_conn_tls_client *)conn;
|
|
|
+ if (tls_client->ssl != NULL) {
|
|
|
+ SSL_free(tls_client->ssl);
|
|
|
+ tls_client->ssl = NULL;
|
|
|
+ }
|
|
|
+ pthread_mutex_destroy(&tls_client->ssl_lock);
|
|
|
+ } else if (conn->type == DNS_CONN_TYPE_TLS_SERVER) {
|
|
|
+ struct dns_server_conn_tls_server *tls_server = (struct dns_server_conn_tls_server *)conn;
|
|
|
+ if (tls_server->ssl_ctx != NULL) {
|
|
|
+ SSL_CTX_free(tls_server->ssl_ctx);
|
|
|
+ tls_server->ssl_ctx = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
list_del_init(&conn->list);
|
|
|
free(conn);
|
|
|
}
|
|
@@ -1007,7 +1061,7 @@ static int _dns_server_reply_tcp(struct dns_request *request, struct dns_server_
|
|
|
memcpy(inpacket + 2, packet, len);
|
|
|
len += 2;
|
|
|
|
|
|
- send_len = send(tcpclient->head.fd, inpacket, len, MSG_NOSIGNAL);
|
|
|
+ send_len = _dns_server_tcp_socket_send(tcpclient, inpacket, len);
|
|
|
if (send_len < 0) {
|
|
|
if (errno == EAGAIN) {
|
|
|
/* save data to buffer, and retry when EPOLLOUT is available */
|
|
@@ -1101,7 +1155,7 @@ static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpac
|
|
|
} else if (conn->type == DNS_CONN_TYPE_TCP_CLIENT) {
|
|
|
ret = _dns_server_reply_tcp(request, (struct dns_server_conn_tcp_client *)conn, inpacket, inpacket_len);
|
|
|
} else if (conn->type == DNS_CONN_TYPE_TLS_CLIENT) {
|
|
|
- ret = -1;
|
|
|
+ ret = _dns_server_reply_tcp(request, (struct dns_server_conn_tcp_client *)conn, inpacket, inpacket_len);
|
|
|
} else {
|
|
|
ret = -1;
|
|
|
}
|
|
@@ -5389,6 +5443,209 @@ errout:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+static ssize_t _ssl_read(struct dns_server_conn_tls_client *conn, void *buff, int num)
|
|
|
+{
|
|
|
+ ssize_t ret = 0;
|
|
|
+ if (conn == NULL || buff == NULL) {
|
|
|
+ return SSL_ERROR_SYSCALL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_mutex_lock(&conn->ssl_lock);
|
|
|
+ ret = SSL_read(conn->ssl, buff, num);
|
|
|
+ pthread_mutex_unlock(&conn->ssl_lock);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t _ssl_write(struct dns_server_conn_tls_client *conn, const void *buff, int num)
|
|
|
+{
|
|
|
+ ssize_t ret = 0;
|
|
|
+ if (conn == NULL || buff == NULL || conn->ssl == NULL) {
|
|
|
+ return SSL_ERROR_SYSCALL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_mutex_lock(&conn->ssl_lock);
|
|
|
+ ret = SSL_write(conn->ssl, buff, num);
|
|
|
+ pthread_mutex_unlock(&conn->ssl_lock);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int _ssl_get_error(struct dns_server_conn_tls_client *conn, int ret)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+ if (conn == NULL || conn->ssl == NULL) {
|
|
|
+ return SSL_ERROR_SYSCALL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_mutex_lock(&conn->ssl_lock);
|
|
|
+ err = SSL_get_error(conn->ssl, ret);
|
|
|
+ pthread_mutex_unlock(&conn->ssl_lock);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int _ssl_do_accept(struct dns_server_conn_tls_client *conn)
|
|
|
+{
|
|
|
+ int err = 0;
|
|
|
+ if (conn == NULL || conn->ssl == NULL) {
|
|
|
+ return SSL_ERROR_SYSCALL;
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_mutex_lock(&conn->ssl_lock);
|
|
|
+ err = SSL_accept(conn->ssl);
|
|
|
+ pthread_mutex_unlock(&conn->ssl_lock);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int _dns_server_socket_ssl_send(struct dns_server_conn_tls_client *tls_client, const void *buf, int num)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ int ssl_ret = 0;
|
|
|
+ unsigned long ssl_err = 0;
|
|
|
+
|
|
|
+ if (tls_client->ssl == NULL) {
|
|
|
+ errno = EINVAL;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (num < 0) {
|
|
|
+ errno = EINVAL;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = _ssl_write(tls_client, buf, num);
|
|
|
+ if (ret > 0) {
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ssl_ret = _ssl_get_error(tls_client, ret);
|
|
|
+ switch (ssl_ret) {
|
|
|
+ case SSL_ERROR_NONE:
|
|
|
+ return 0;
|
|
|
+ break;
|
|
|
+ case SSL_ERROR_ZERO_RETURN:
|
|
|
+ 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();
|
|
|
+ int ssl_reason = ERR_GET_REASON(ssl_err);
|
|
|
+ if (ssl_reason == SSL_R_UNINITIALIZED || ssl_reason == SSL_R_PROTOCOL_IS_SHUTDOWN ||
|
|
|
+ ssl_reason == SSL_R_BAD_LENGTH || ssl_reason == SSL_R_SHUTDOWN_WHILE_IN_INIT ||
|
|
|
+ ssl_reason == SSL_R_BAD_WRITE_RETRY) {
|
|
|
+ errno = EAGAIN;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ tlog(TLOG_ERROR, "SSL write fail error no: %s(%d)\n", ERR_reason_error_string(ssl_err), ssl_reason);
|
|
|
+ errno = EFAULT;
|
|
|
+ ret = -1;
|
|
|
+ break;
|
|
|
+ case SSL_ERROR_SYSCALL:
|
|
|
+ tlog(TLOG_DEBUG, "SSL syscall failed, %s", strerror(errno));
|
|
|
+ return ret;
|
|
|
+ default:
|
|
|
+ errno = EFAULT;
|
|
|
+ ret = -1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int _dns_server_socket_ssl_recv(struct dns_server_conn_tls_client *tls_client, void *buf, int num)
|
|
|
+{
|
|
|
+ ssize_t ret = 0;
|
|
|
+ int ssl_ret = 0;
|
|
|
+ unsigned long ssl_err = 0;
|
|
|
+
|
|
|
+ if (tls_client->ssl == NULL) {
|
|
|
+ errno = EFAULT;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = _ssl_read(tls_client, buf, num);
|
|
|
+ if (ret >= 0) {
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ssl_ret = _ssl_get_error(tls_client, ret);
|
|
|
+ switch (ssl_ret) {
|
|
|
+ case SSL_ERROR_NONE:
|
|
|
+ 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();
|
|
|
+ int ssl_reason = ERR_GET_REASON(ssl_err);
|
|
|
+ if (ssl_reason == SSL_R_UNINITIALIZED) {
|
|
|
+ errno = EAGAIN;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ssl_reason == SSL_R_SHUTDOWN_WHILE_IN_INIT || ssl_reason == SSL_R_PROTOCOL_IS_SHUTDOWN) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ tlog(TLOG_INFO, "SSL read fail error no: %s(%lx), len: %d\n", ERR_reason_error_string(ssl_err), ssl_err, num);
|
|
|
+ errno = EFAULT;
|
|
|
+ ret = -1;
|
|
|
+ break;
|
|
|
+ case SSL_ERROR_SYSCALL:
|
|
|
+ if (errno == 0) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (errno != ECONNRESET) {
|
|
|
+ tlog(TLOG_INFO, "SSL syscall failed, %s ", strerror(errno));
|
|
|
+ }
|
|
|
+ ret = -1;
|
|
|
+ return ret;
|
|
|
+ default:
|
|
|
+ errno = EFAULT;
|
|
|
+ ret = -1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int _dns_server_tcp_socket_send(struct dns_server_conn_tcp_client *tcp_client, void *data, int data_len)
|
|
|
+{
|
|
|
+ if (tcp_client->head.type == DNS_CONN_TYPE_TCP_CLIENT) {
|
|
|
+ return send(tcp_client->head.fd, data, data_len, MSG_NOSIGNAL);
|
|
|
+ } else if (tcp_client->head.type == DNS_CONN_TYPE_TLS_CLIENT ||
|
|
|
+ tcp_client->head.type == DNS_CONN_TYPE_HTTPS_CLIENT) {
|
|
|
+ int ret = _dns_server_socket_ssl_send((struct dns_server_conn_tls_client *)tcp_client, data, data_len);
|
|
|
+ return ret;
|
|
|
+ } else {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int _dns_server_tcp_socket_recv(struct dns_server_conn_tcp_client *tcp_client, void *data, int data_len)
|
|
|
+{
|
|
|
+ if (tcp_client->head.type == DNS_CONN_TYPE_TCP_CLIENT) {
|
|
|
+ return recv(tcp_client->head.fd, data, data_len, MSG_NOSIGNAL);
|
|
|
+ } else if (tcp_client->head.type == DNS_CONN_TYPE_TLS_CLIENT ||
|
|
|
+ tcp_client->head.type == DNS_CONN_TYPE_HTTPS_CLIENT) {
|
|
|
+ return _dns_server_socket_ssl_recv((struct dns_server_conn_tls_client *)tcp_client, data, data_len);
|
|
|
+ } else {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int _dns_server_tcp_recv(struct dns_server_conn_tcp_client *tcpclient)
|
|
|
{
|
|
|
ssize_t len = 0;
|
|
@@ -5399,8 +5656,8 @@ static int _dns_server_tcp_recv(struct dns_server_conn_tcp_client *tcpclient)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- len = recv(tcpclient->head.fd, tcpclient->recvbuff.buf + tcpclient->recvbuff.size,
|
|
|
- sizeof(tcpclient->recvbuff.buf) - tcpclient->recvbuff.size, 0);
|
|
|
+ len = _dns_server_tcp_socket_recv(tcpclient, tcpclient->recvbuff.buf + tcpclient->recvbuff.size,
|
|
|
+ sizeof(tcpclient->recvbuff.buf) - tcpclient->recvbuff.size);
|
|
|
if (len < 0) {
|
|
|
if (errno == EAGAIN) {
|
|
|
return RECV_ERROR_AGAIN;
|
|
@@ -5517,7 +5774,7 @@ static int _dns_server_tcp_send(struct dns_server_conn_tcp_client *tcpclient)
|
|
|
{
|
|
|
int len = 0;
|
|
|
while (tcpclient->sndbuff.size > 0) {
|
|
|
- len = send(tcpclient->head.fd, tcpclient->sndbuff.buf, tcpclient->sndbuff.size, MSG_NOSIGNAL);
|
|
|
+ len = _dns_server_tcp_socket_send(tcpclient, tcpclient->sndbuff.buf, tcpclient->sndbuff.size);
|
|
|
if (len < 0) {
|
|
|
if (errno == EAGAIN) {
|
|
|
return RECV_ERROR_AGAIN;
|
|
@@ -5566,6 +5823,137 @@ static int _dns_server_process_tcp(struct dns_server_conn_tcp_client *dnsserver,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int _dns_server_tls_accept(struct dns_server_conn_tls_server *tls_server, struct epoll_event *event,
|
|
|
+ unsigned long now)
|
|
|
+{
|
|
|
+ struct sockaddr_storage addr;
|
|
|
+ struct dns_server_conn_tls_client *tls_client = NULL;
|
|
|
+ socklen_t addr_len = sizeof(addr);
|
|
|
+ int fd = -1;
|
|
|
+ SSL *ssl = NULL;
|
|
|
+
|
|
|
+ fd = accept4(tls_server->head.fd, (struct sockaddr *)&addr, &addr_len, SOCK_NONBLOCK | SOCK_CLOEXEC);
|
|
|
+ if (fd < 0) {
|
|
|
+ tlog(TLOG_ERROR, "accept failed, %s", strerror(errno));
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ tls_client = malloc(sizeof(*tls_client));
|
|
|
+ if (tls_client == NULL) {
|
|
|
+ tlog(TLOG_ERROR, "malloc for tls_client failed.");
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ memset(tls_client, 0, sizeof(*tls_client));
|
|
|
+
|
|
|
+ tls_client->head.fd = fd;
|
|
|
+ tls_client->head.type = DNS_CONN_TYPE_TLS_CLIENT;
|
|
|
+ tls_client->head.server_flags = tls_server->head.server_flags;
|
|
|
+ tls_client->head.dns_group = tls_server->head.dns_group;
|
|
|
+ atomic_set(&tls_client->head.refcnt, 0);
|
|
|
+ memcpy(&tls_client->addr, &addr, addr_len);
|
|
|
+ tls_client->addr_len = addr_len;
|
|
|
+ tls_client->localaddr_len = sizeof(struct sockaddr_storage);
|
|
|
+ if (_dns_server_epoll_ctl(&tls_client->head, EPOLL_CTL_ADD, EPOLLIN) != 0) {
|
|
|
+ tlog(TLOG_ERROR, "epoll ctl failed.");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (getsocket_inet(tls_client->head.fd, (struct sockaddr *)&tls_client->localaddr, &tls_client->localaddr_len) !=
|
|
|
+ 0) {
|
|
|
+ tlog(TLOG_ERROR, "get local addr failed, %s", strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ ssl = SSL_new(tls_server->ssl_ctx);
|
|
|
+ if (ssl == NULL) {
|
|
|
+ tlog(TLOG_ERROR, "SSL_new failed.");
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (SSL_set_fd(ssl, fd) != 1) {
|
|
|
+ tlog(TLOG_ERROR, "SSL_set_fd failed.");
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ tls_client->ssl = ssl;
|
|
|
+ tls_client->status = DNS_SERVER_CLIENT_STATUS_CONNECTING;
|
|
|
+ pthread_mutex_init(&tls_client->ssl_lock, NULL);
|
|
|
+ _dns_server_client_touch(&tls_client->head);
|
|
|
+
|
|
|
+ list_add(&tls_client->head.list, &server.conn_list);
|
|
|
+ _dns_server_conn_get(&tls_client->head);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+errout:
|
|
|
+ if (fd > 0) {
|
|
|
+ close(fd);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ssl) {
|
|
|
+ SSL_free(ssl);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tls_client) {
|
|
|
+ free(tls_client);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+static int _dns_server_process_tls(struct dns_server_conn_tls_client *tls_client, struct epoll_event *event,
|
|
|
+ unsigned long now)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+ int ssl_ret = 0;
|
|
|
+ struct epoll_event fd_event;
|
|
|
+
|
|
|
+ if (tls_client->status == DNS_SERVER_CLIENT_STATUS_CONNECTING) {
|
|
|
+ /* do SSL hand shake */
|
|
|
+ ret = _ssl_do_accept(tls_client);
|
|
|
+ if (ret == 0) {
|
|
|
+ goto errout;
|
|
|
+ } else if (ret < 0) {
|
|
|
+ memset(&fd_event, 0, sizeof(fd_event));
|
|
|
+ ssl_ret = _ssl_get_error(tls_client, ret);
|
|
|
+ if (ssl_ret == SSL_ERROR_WANT_READ) {
|
|
|
+ fd_event.events = EPOLLIN;
|
|
|
+ } else if (ssl_ret == SSL_ERROR_WANT_WRITE) {
|
|
|
+ fd_event.events = EPOLLOUT | EPOLLIN;
|
|
|
+ } else if (ssl_ret == SSL_ERROR_SYSCALL) {
|
|
|
+ goto errout;
|
|
|
+ } else {
|
|
|
+ unsigned long ssl_err = ERR_get_error();
|
|
|
+ int ssl_reason = ERR_GET_REASON(ssl_err);
|
|
|
+ tlog(TLOG_DEBUG, "Handshake with %s failed, error no: %s(%d, %d, %d)\n", "",
|
|
|
+ ERR_reason_error_string(ssl_err), ret, ssl_ret, ssl_reason);
|
|
|
+ ret = 0;
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ fd_event.data.ptr = tls_client;
|
|
|
+ if (epoll_ctl(server.epoll_fd, EPOLL_CTL_MOD, tls_client->head.fd, &fd_event) != 0) {
|
|
|
+ tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ tls_client->status = DNS_SERVER_CLIENT_STATUS_CONNECTED;
|
|
|
+ memset(&fd_event, 0, sizeof(fd_event));
|
|
|
+ fd_event.events = EPOLLIN | EPOLLOUT;
|
|
|
+ fd_event.data.ptr = tls_client;
|
|
|
+ if (epoll_ctl(server.epoll_fd, EPOLL_CTL_MOD, tls_client->head.fd, &fd_event) != 0) {
|
|
|
+ tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return _dns_server_process_tcp((struct dns_server_conn_tcp_client *)tls_client, event, now);
|
|
|
+errout:
|
|
|
+ _dns_server_client_close(&tls_client->head);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int _dns_server_process(struct dns_server_conn_head *conn, struct epoll_event *event, unsigned long now)
|
|
|
{
|
|
|
int ret = 0;
|
|
@@ -5586,10 +5974,19 @@ static int _dns_server_process(struct dns_server_conn_head *conn, struct epoll_e
|
|
|
get_host_by_addr(name, sizeof(name), (struct sockaddr *)&tcpclient->addr));
|
|
|
}
|
|
|
} else if (conn->type == DNS_CONN_TYPE_TLS_SERVER) {
|
|
|
- tlog(TLOG_ERROR, "unsupported dns server type %d", conn->type);
|
|
|
- ret = -1;
|
|
|
+ struct dns_server_conn_tls_server *tls_server = (struct dns_server_conn_tls_server *)conn;
|
|
|
+ ret = _dns_server_tls_accept(tls_server, event, now);
|
|
|
+ } else if (conn->type == DNS_CONN_TYPE_TLS_CLIENT) {
|
|
|
+ struct dns_server_conn_tls_client *tls_client = (struct dns_server_conn_tls_client *)conn;
|
|
|
+ ret = _dns_server_process_tls(tls_client, event, now);
|
|
|
+ if (ret != 0) {
|
|
|
+ char name[DNS_MAX_CNAME_LEN];
|
|
|
+ tlog(TLOG_DEBUG, "process TLS packet from %s failed.",
|
|
|
+ get_host_by_addr(name, sizeof(name), (struct sockaddr *)&tls_client->addr));
|
|
|
+ }
|
|
|
} else {
|
|
|
tlog(TLOG_ERROR, "unsupported dns server type %d", conn->type);
|
|
|
+ _dns_server_client_close(conn);
|
|
|
ret = -1;
|
|
|
}
|
|
|
_dns_server_conn_release(conn);
|
|
@@ -5818,9 +6215,18 @@ static void _dns_server_close_socket_server(void)
|
|
|
list_for_each_entry_safe(conn, tmp, &server.conn_list, list)
|
|
|
{
|
|
|
switch (conn->type) {
|
|
|
+ case DNS_CONN_TYPE_HTTPS_SERVER:
|
|
|
+ case DNS_CONN_TYPE_TLS_SERVER: {
|
|
|
+ struct dns_server_conn_tls_server *tls_server = (struct dns_server_conn_tls_server *)conn;
|
|
|
+ if (tls_server->ssl_ctx) {
|
|
|
+ SSL_CTX_free(tls_server->ssl_ctx);
|
|
|
+ tls_server->ssl_ctx = NULL;
|
|
|
+ }
|
|
|
+ _dns_server_client_close(conn);
|
|
|
+ break;
|
|
|
+ }
|
|
|
case DNS_CONN_TYPE_UDP_SERVER:
|
|
|
case DNS_CONN_TYPE_TCP_SERVER:
|
|
|
- case DNS_CONN_TYPE_TLS_SERVER:
|
|
|
_dns_server_client_close(conn);
|
|
|
break;
|
|
|
default:
|
|
@@ -6113,6 +6519,7 @@ static int _dns_server_socket_tcp(struct dns_bind_ip *bind_ip)
|
|
|
const char *host_ip = NULL;
|
|
|
struct dns_server_conn_tcp_server *conn = NULL;
|
|
|
int fd = -1;
|
|
|
+ const int on = 1;
|
|
|
|
|
|
host_ip = bind_ip->ip;
|
|
|
conn = malloc(sizeof(struct dns_server_conn_tcp_server));
|
|
@@ -6126,6 +6533,8 @@ static int _dns_server_socket_tcp(struct dns_bind_ip *bind_ip)
|
|
|
goto errout;
|
|
|
}
|
|
|
|
|
|
+ setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &on, sizeof(on));
|
|
|
+
|
|
|
conn->head.type = DNS_CONN_TYPE_TCP_SERVER;
|
|
|
conn->head.fd = fd;
|
|
|
_dns_server_set_flags(&conn->head, bind_ip);
|
|
@@ -6144,6 +6553,110 @@ errout:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+static int _dns_server_socket_tls_ssl_pass_callback(char *buf, int size, int rwflag, void *userdata)
|
|
|
+{
|
|
|
+ struct dns_bind_ip *bind_ip = userdata;
|
|
|
+ if (bind_ip->ssl_cert_key_pass == NULL || bind_ip->ssl_cert_key_pass[0] == '\0') {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ safe_strncpy(buf, bind_ip->ssl_cert_key_pass, size);
|
|
|
+ return strlen(buf);
|
|
|
+}
|
|
|
+
|
|
|
+static int _dns_server_socket_tls(struct dns_bind_ip *bind_ip, DNS_CONN_TYPE conn_type)
|
|
|
+{
|
|
|
+ const char *host_ip = NULL;
|
|
|
+ const char *ssl_cert_file = NULL;
|
|
|
+ const char *ssl_cert_key_file = NULL;
|
|
|
+
|
|
|
+ struct dns_server_conn_tls_server *conn = NULL;
|
|
|
+ int fd = -1;
|
|
|
+ const SSL_METHOD *method = NULL;
|
|
|
+ SSL_CTX *ssl_ctx = NULL;
|
|
|
+ const int on = 1;
|
|
|
+
|
|
|
+ host_ip = bind_ip->ip;
|
|
|
+ ssl_cert_file = bind_ip->ssl_cert_file;
|
|
|
+ ssl_cert_key_file = bind_ip->ssl_cert_key_file;
|
|
|
+
|
|
|
+ if (ssl_cert_file == NULL || ssl_cert_key_file == NULL) {
|
|
|
+ tlog(TLOG_WARN, "no cert or cert key file");
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ssl_cert_file[0] == '\0' || ssl_cert_key_file[0] == '\0') {
|
|
|
+ tlog(TLOG_WARN, "no cert or cert key file");
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ conn = malloc(sizeof(struct dns_server_conn_tls_server));
|
|
|
+ if (conn == NULL) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ INIT_LIST_HEAD(&conn->head.list);
|
|
|
+
|
|
|
+ fd = _dns_create_socket(host_ip, SOCK_STREAM);
|
|
|
+ if (fd <= 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &on, sizeof(on));
|
|
|
+
|
|
|
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
|
|
+ method = TLS_server_method();
|
|
|
+ if (method == NULL) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ method = SSLv23_server_method();
|
|
|
+#endif
|
|
|
+
|
|
|
+ ssl_ctx = SSL_CTX_new(method);
|
|
|
+ if (ssl_ctx == NULL) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ SSL_CTX_set_session_cache_mode(ssl_ctx,
|
|
|
+ SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR);
|
|
|
+ SSL_CTX_set_default_passwd_cb(ssl_ctx, _dns_server_socket_tls_ssl_pass_callback);
|
|
|
+ SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, bind_ip);
|
|
|
+
|
|
|
+ /* Set the key and cert */
|
|
|
+ if (ssl_cert_file[0] != '\0' && SSL_CTX_use_certificate_file(ssl_ctx, ssl_cert_file, SSL_FILETYPE_PEM) <= 0) {
|
|
|
+ tlog(TLOG_ERROR, "load cert %s failed, %s", ssl_cert_file, ERR_error_string(ERR_get_error(), NULL));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ssl_cert_key_file[0] != '\0' &&
|
|
|
+ SSL_CTX_use_PrivateKey_file(ssl_ctx, ssl_cert_key_file, SSL_FILETYPE_PEM) <= 0) {
|
|
|
+ tlog(TLOG_ERROR, "load cert key %s failed, %s", ssl_cert_key_file, ERR_error_string(ERR_get_error(), NULL));
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+
|
|
|
+ conn->head.type = conn_type;
|
|
|
+ conn->head.fd = fd;
|
|
|
+ conn->ssl_ctx = ssl_ctx;
|
|
|
+ _dns_server_set_flags(&conn->head, bind_ip);
|
|
|
+ _dns_server_conn_get(&conn->head);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+errout:
|
|
|
+ if (ssl_ctx) {
|
|
|
+ SSL_CTX_free(ssl_ctx);
|
|
|
+ ssl_ctx = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (conn) {
|
|
|
+ free(conn);
|
|
|
+ conn = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fd > 0) {
|
|
|
+ close(fd);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
static int _dns_server_socket(void)
|
|
|
{
|
|
|
int i = 0;
|
|
@@ -6161,7 +6674,15 @@ static int _dns_server_socket(void)
|
|
|
goto errout;
|
|
|
}
|
|
|
break;
|
|
|
+ case DNS_BIND_TYPE_HTTPS:
|
|
|
+ if (_dns_server_socket_tls(bind_ip, DNS_CONN_TYPE_HTTPS_SERVER) != 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
+ break;
|
|
|
case DNS_BIND_TYPE_TLS:
|
|
|
+ if (_dns_server_socket_tls(bind_ip, DNS_CONN_TYPE_TLS_SERVER) != 0) {
|
|
|
+ goto errout;
|
|
|
+ }
|
|
|
break;
|
|
|
default:
|
|
|
break;
|