Compare commits
4 Commits
Release32-
...
Release32-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a9829f6155 | ||
|
|
1923271630 | ||
|
|
c23ec7ea8f | ||
|
|
aad751c1f5 |
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM debian:buster-slim
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y git make gcc libssl-dev && \
|
||||
git clone https://github.com/pymumu/smartdns.git --depth 1 && \
|
||||
cd smartdns && \
|
||||
sh ./package/build-pkg.sh --platform debian --arch `dpkg --print-architecture` && \
|
||||
dpkg -i package/*.deb && \
|
||||
cd / && \
|
||||
rm -rf smartdns/ && \
|
||||
apt autoremove -y git make gcc libssl-dev && \
|
||||
apt clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
EXPOSE 53/udp
|
||||
VOLUME "/etc/smartdns/"
|
||||
|
||||
CMD ["/usr/sbin/smartdns", "-f"]
|
||||
@@ -110,7 +110,7 @@ struct dns_head {
|
||||
unsigned short ancount; /* number of answer entries */
|
||||
unsigned short nscount; /* number of authority entries */
|
||||
unsigned short nrcount; /* number of addititional resource entries */
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed, aligned(2)));
|
||||
|
||||
struct dns_rrs {
|
||||
unsigned short next;
|
||||
|
||||
@@ -860,7 +860,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
}
|
||||
|
||||
SSL_CTX_set_options(server_info->ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
|
||||
SSL_CTX_set_session_cache_mode(server_info->ssl_ctx, SSL_SESS_CACHE_CLIENT);
|
||||
if (_dns_client_set_trusted_cert(server_info->ssl_ctx) != 0) {
|
||||
tlog(TLOG_WARN, "disable check certificate for %s.", server_info->ip);
|
||||
server_info->skip_check_cert = 1;
|
||||
@@ -1513,6 +1513,11 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
set_sock_keepalive(fd, 15, 3, 4);
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (errno == ENETUNREACH) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
@@ -1585,6 +1590,11 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos));
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (errno == ENETUNREACH) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
@@ -1628,7 +1638,6 @@ errout:
|
||||
}
|
||||
|
||||
if (ssl) {
|
||||
SSL_shutdown(ssl);
|
||||
SSL_free(ssl);
|
||||
}
|
||||
|
||||
@@ -1729,17 +1738,19 @@ static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num)
|
||||
unsigned long ssl_err = 0;
|
||||
|
||||
if (ssl == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = SSL_write(ssl, buf, num);
|
||||
if (ret >= 0) {
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssl_ret = SSL_get_error(ssl, ret);
|
||||
switch (ssl_ret) {
|
||||
case SSL_ERROR_NONE:
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return 0;
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
@@ -1752,12 +1763,14 @@ static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num)
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
ssl_err = ERR_get_error();
|
||||
if (ERR_GET_REASON(ssl_err) == SSL_R_UNINITIALIZED || ERR_GET_REASON(ssl_err) == SSL_R_PROTOCOL_IS_SHUTDOWN) {
|
||||
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) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "SSL write fail error no: %s(%ld)\n", ERR_reason_error_string(ssl_err), ssl_err);
|
||||
tlog(TLOG_ERROR, "SSL write fail error no: %s(%d)\n", ERR_reason_error_string(ssl_err), ssl_reason);
|
||||
errno = EFAULT;
|
||||
ret = -1;
|
||||
break;
|
||||
@@ -1792,8 +1805,6 @@ static int _dns_client_socket_ssl_recv(SSL *ssl, void *buf, int num)
|
||||
ssl_ret = SSL_get_error(ssl, ret);
|
||||
switch (ssl_ret) {
|
||||
case SSL_ERROR_NONE:
|
||||
return 0;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return 0;
|
||||
break;
|
||||
@@ -1807,11 +1818,16 @@ static int _dns_client_socket_ssl_recv(SSL *ssl, void *buf, int num)
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
ssl_err = ERR_get_error();
|
||||
if (ERR_GET_REASON(ssl_err) == SSL_R_UNINITIALIZED) {
|
||||
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_ERROR, "SSL read fail error no: %s(%ld)\n", ERR_reason_error_string(ssl_err), ssl_err);
|
||||
errno = EFAULT;
|
||||
ret = -1;
|
||||
@@ -2099,11 +2115,30 @@ static int _dns_client_tls_matchName(const char *host, const char *pattern, int
|
||||
return match;
|
||||
}
|
||||
|
||||
static int _dns_client_tls_get_cert_CN(X509 *cert, char *cn, int max_cn_len) {
|
||||
X509_NAME *cert_name = NULL;
|
||||
|
||||
cert_name = X509_get_subject_name(cert);
|
||||
if (cert_name == NULL) {
|
||||
tlog(TLOG_ERROR, "get subject name failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (X509_NAME_get_text_by_NID(cert_name, NID_commonName, cn, max_cn_len) == -1) {
|
||||
tlog(TLOG_ERROR, "cannot found x509 name");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
X509_PUBKEY *pubkey = NULL;
|
||||
X509_NAME *cert_name = NULL;
|
||||
char peer_CN[256];
|
||||
char cert_fingerprint[256];
|
||||
int i = 0;
|
||||
@@ -2127,24 +2162,20 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
if (server_info->skip_check_cert == 0) {
|
||||
long res = SSL_get_verify_result(server_info->ssl);
|
||||
if (res != X509_V_OK) {
|
||||
tlog(TLOG_WARN, "peer server certificate verify failed.");
|
||||
peer_CN[0] = '\0';
|
||||
_dns_client_tls_get_cert_CN(cert, peer_CN, sizeof(peer_CN));
|
||||
tlog(TLOG_WARN, "peer server %s certificate verify failed", server_info->ip);
|
||||
tlog(TLOG_WARN, "peer CN: %s", peer_CN);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
cert_name = X509_get_subject_name(cert);
|
||||
if (cert_name == NULL) {
|
||||
tlog(TLOG_ERROR, "get subject name failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (X509_NAME_get_text_by_NID(cert_name, NID_commonName, peer_CN, 256) == -1) {
|
||||
tlog(TLOG_ERROR, "cannot found x509 name");
|
||||
if (_dns_client_tls_get_cert_CN(cert, peer_CN, sizeof(peer_CN)) != 0) {
|
||||
tlog(TLOG_ERROR, "get cert CN failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "peer CN: %s", peer_CN);
|
||||
|
||||
/* check tls host */
|
||||
tls_host_verify = _dns_client_server_get_tls_host_verify(server_info);
|
||||
if (tls_host_verify) {
|
||||
@@ -2247,10 +2278,16 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
fd_event.events = EPOLLIN;
|
||||
} else if (ssl_ret == SSL_ERROR_WANT_WRITE) {
|
||||
fd_event.events = EPOLLOUT | EPOLLIN;
|
||||
} else if (ssl_ret == SSL_ERROR_SYSCALL) {
|
||||
if (errno != ENETUNREACH) {
|
||||
tlog(TLOG_WARN, "Handshake with %s failed, %s", server_info->ip, strerror(errno));
|
||||
}
|
||||
goto errout;
|
||||
} else {
|
||||
unsigned long ssl_err = ERR_get_error();
|
||||
tlog(TLOG_ERROR, "Handshake with %s failed, error no: %s(%ld)\n", server_info->ip,
|
||||
ERR_reason_error_string(ssl_err), ssl_err);
|
||||
int ssl_reason = ERR_GET_REASON(ssl_err);
|
||||
tlog(TLOG_WARN, "Handshake with %s failed, error no: %s(%d, %d, %d)\n", server_info->ip,
|
||||
ERR_reason_error_string(ssl_err), ret, ssl_ret, ssl_reason);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -2289,7 +2326,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTED;
|
||||
memset(&fd_event, 0, sizeof(fd_event));
|
||||
fd_event.events = EPOLLIN;
|
||||
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, %s", strerror(errno));
|
||||
@@ -2430,11 +2467,12 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
|
||||
}
|
||||
|
||||
if (server_info->ssl == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, len);
|
||||
if (send_len < 0) {
|
||||
if (send_len <= 0) {
|
||||
if (errno == EAGAIN || errno == EPIPE || 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);
|
||||
@@ -2480,11 +2518,12 @@ static int _dns_client_send_https(struct dns_server_info *server_info, void *pac
|
||||
}
|
||||
|
||||
if (server_info->ssl == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, http_len);
|
||||
if (send_len < 0) {
|
||||
if (send_len <= 0) {
|
||||
if (errno == EAGAIN || errno == EPIPE || server_info->ssl == NULL) {
|
||||
/* save data to buffer, and retry when EPOLLOUT is available */
|
||||
return _dns_client_send_data_to_buffer(server_info, inpacket, http_len);
|
||||
@@ -2507,11 +2546,12 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
struct dns_server_group_member *tmp = NULL;
|
||||
int ret = 0;
|
||||
int send_err = 0;
|
||||
int i = 0;
|
||||
|
||||
query->send_tick = get_tick_count();
|
||||
|
||||
/* send query to all dns servers */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
pthread_mutex_lock(&client.server_list_lock);
|
||||
list_for_each_entry_safe(group_member, tmp, &query->server_group->head, list)
|
||||
{
|
||||
@@ -2552,7 +2592,11 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (send_err != ENOMEM) {
|
||||
if (send_err == ENETUNREACH) {
|
||||
tlog(TLOG_DEBUG, "send query to %s failed, %s, type: %d", server_info->ip, strerror(send_err),
|
||||
server_info->type);
|
||||
_dns_client_close_socket(server_info);
|
||||
} else if (send_err != ENOMEM) {
|
||||
tlog(TLOG_ERROR, "send query to %s failed, %s, type: %d", server_info->ip, strerror(send_err),
|
||||
server_info->type);
|
||||
} else {
|
||||
|
||||
@@ -262,6 +262,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip = argv[1];
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
tlog(TLOG_WARN, "exceeds max server number, %s", ip);
|
||||
return 0;
|
||||
@@ -274,8 +275,6 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
server->httphost[0] = '\0';
|
||||
server->tls_host_verify[0] = '\0';
|
||||
|
||||
ip = argv[1];
|
||||
|
||||
if (type == DNS_SERVER_HTTPS) {
|
||||
if (parse_uri(ip, NULL, server->server, &port, server->path) != 0) {
|
||||
return -1;
|
||||
@@ -871,6 +870,7 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ip = argv[1];
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
tlog(TLOG_WARN, "exceeds max server number, %s", ip);
|
||||
return 0;
|
||||
@@ -879,7 +879,6 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
bind_ip = &dns_conf_bind_ip[index];
|
||||
bind_ip->type = type;
|
||||
bind_ip->flags = 0;
|
||||
ip = argv[1];
|
||||
safe_strncpy(bind_ip->ip, ip, DNS_MAX_IPLEN);
|
||||
|
||||
/* process extra options */
|
||||
|
||||
@@ -880,6 +880,7 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
|
||||
|
||||
/* Return the most likely correct IP address */
|
||||
/* Returns the IP with the most hits, or the last returned record is considered to be the most likely correct. */
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
{
|
||||
if (addr_map->addr_type != request->qtype) {
|
||||
@@ -896,6 +897,7 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
|
||||
maxhit_addr_map = addr_map;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
|
||||
if (maxhit_addr_map && maxhit > 1) {
|
||||
selected_addr_map = maxhit_addr_map;
|
||||
@@ -966,11 +968,13 @@ static void _dns_server_request_release_complete(struct dns_request *request, in
|
||||
_dns_server_request_complete(request);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
{
|
||||
hash_del(&addr_map->node);
|
||||
free(addr_map);
|
||||
}
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
|
||||
_dns_server_delete_request(request);
|
||||
}
|
||||
@@ -2009,7 +2013,7 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _dns_server_prolcess_speed_check_rule(struct dns_request *request)
|
||||
static void _dns_server_process_speed_check_rule(struct dns_request *request)
|
||||
{
|
||||
struct dns_domain_check_order *check_order = NULL;
|
||||
|
||||
@@ -2257,7 +2261,7 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain,
|
||||
}
|
||||
|
||||
/* process speed check rule */
|
||||
_dns_server_prolcess_speed_check_rule(request);
|
||||
_dns_server_process_speed_check_rule(request);
|
||||
|
||||
/* check and set passthrough */
|
||||
_dns_server_check_set_passthrough(request);
|
||||
|
||||
Reference in New Issue
Block a user