proxy: simple add socks5 and https proxy support
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
BIN=smartdns
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o lib/nftset.o
|
||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o $(OBJS_LIB)
|
||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o $(OBJS_LIB)
|
||||
|
||||
# cflags
|
||||
ifndef CFLAGS
|
||||
|
||||
373
src/dns_client.c
373
src/dns_client.c
@@ -26,6 +26,7 @@
|
||||
#include "hashtable.h"
|
||||
#include "http_parse.h"
|
||||
#include "list.h"
|
||||
#include "proxy.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <arpa/inet.h>
|
||||
@@ -91,6 +92,7 @@ struct dns_server_info {
|
||||
|
||||
char ip[DNS_HOSTNAME_LEN];
|
||||
int port;
|
||||
char proxy_name[DNS_HOSTNAME_LEN];
|
||||
/* server type */
|
||||
dns_server_type_t type;
|
||||
long long so_mark;
|
||||
@@ -103,6 +105,9 @@ struct dns_server_info {
|
||||
int ssl_write_len;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL_SESSION *ssl_session;
|
||||
|
||||
struct proxy_conn *proxy;
|
||||
|
||||
pthread_mutex_t lock;
|
||||
char skip_check_cert;
|
||||
dns_server_status status;
|
||||
@@ -254,6 +259,8 @@ static LIST_HEAD(pending_servers);
|
||||
static pthread_mutex_t pending_server_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int dns_client_has_bootstrap_dns = 0;
|
||||
|
||||
static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len);
|
||||
|
||||
static ssize_t _ssl_read(struct dns_server_info *server, void *buff, int num)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
@@ -1047,6 +1054,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
server_info->skip_check_cert = skip_check_cert;
|
||||
server_info->prohibit = 0;
|
||||
server_info->so_mark = flags->set_mark;
|
||||
safe_strncpy(server_info->proxy_name, flags->proxyname, sizeof(server_info->proxy_name));
|
||||
pthread_mutex_init(&server_info->lock, NULL);
|
||||
memcpy(&server_info->flags, flags, sizeof(server_info->flags));
|
||||
|
||||
@@ -1141,7 +1149,13 @@ static void _dns_client_close_socket(struct dns_server_info *server_info)
|
||||
|
||||
/* remove fd from epoll */
|
||||
epoll_ctl(client.epoll_fd, EPOLL_CTL_DEL, server_info->fd, NULL);
|
||||
close(server_info->fd);
|
||||
|
||||
if (server_info->proxy) {
|
||||
proxy_conn_free(server_info->proxy);
|
||||
server_info->proxy = NULL;
|
||||
} else {
|
||||
close(server_info->fd);
|
||||
}
|
||||
|
||||
server_info->fd = -1;
|
||||
server_info->status = DNS_SERVER_STATUS_DISCONNECTED;
|
||||
@@ -1670,6 +1684,69 @@ static int _dns_client_recv(struct dns_server_info *server_info, unsigned char *
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_create_socket_udp_proxy(struct dns_server_info *server_info)
|
||||
{
|
||||
struct proxy_conn *proxy = NULL;
|
||||
int fd = -1;
|
||||
struct epoll_event event;
|
||||
int ret = -1;
|
||||
|
||||
proxy = proxy_conn_new(server_info->proxy_name, server_info->ip, server_info->port, 1);
|
||||
if (proxy == NULL) {
|
||||
tlog(TLOG_ERROR, "create proxy failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
fd = proxy_conn_get_fd(proxy);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "get proxy fd failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (server_info->so_mark >= 0) {
|
||||
unsigned int so_mark = server_info->so_mark;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) != 0) {
|
||||
tlog(TLOG_DEBUG, "set socket mark failed, %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
set_fd_nonblock(fd, 1);
|
||||
set_sock_keepalive(fd, 15, 3, 4);
|
||||
|
||||
ret = proxy_conn_connect(proxy);
|
||||
if (ret != 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;
|
||||
}
|
||||
}
|
||||
|
||||
server_info->fd = fd;
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||
server_info->proxy = proxy;
|
||||
|
||||
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, %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (proxy) {
|
||||
proxy_conn_free(proxy);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_client_create_socket_udp(struct dns_server_info *server_info)
|
||||
{
|
||||
int fd = 0;
|
||||
@@ -1679,6 +1756,10 @@ static int _dns_client_create_socket_udp(struct dns_server_info *server_info)
|
||||
const int priority = SOCKET_PRIORITY;
|
||||
const int ip_tos = SOCKET_IP_TOS;
|
||||
|
||||
if (server_info->proxy_name[0] != '\0') {
|
||||
return _dns_client_create_socket_udp_proxy(server_info);
|
||||
}
|
||||
|
||||
fd = socket(server_info->ai_family, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "create socket failed, %s", strerror(errno));
|
||||
@@ -1750,8 +1831,20 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
int yes = 1;
|
||||
const int priority = SOCKET_PRIORITY;
|
||||
const int ip_tos = SOCKET_IP_TOS;
|
||||
struct proxy_conn *proxy = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (server_info->proxy_name[0] != '\0') {
|
||||
proxy = proxy_conn_new(server_info->proxy_name, server_info->ip, server_info->port, 0);
|
||||
if (proxy == NULL) {
|
||||
tlog(TLOG_ERROR, "create proxy failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
fd = proxy_conn_get_fd(proxy);
|
||||
} else {
|
||||
fd = socket(server_info->ai_family, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
fd = socket(server_info->ai_family, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "create socket failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
@@ -1781,8 +1874,14 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes));
|
||||
set_sock_keepalive(fd, 15, 3, 4);
|
||||
|
||||
if (connect(fd, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (errno == ENETUNREACH || errno == EHOSTUNREACH) {
|
||||
if (proxy) {
|
||||
ret = proxy_conn_connect(proxy);
|
||||
} else {
|
||||
ret = connect(fd, &server_info->addr, server_info->ai_addrlen);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
@@ -1795,6 +1894,7 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
|
||||
server_info->fd = fd;
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||
server_info->proxy = proxy;
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLOUT;
|
||||
@@ -1814,9 +1914,14 @@ errout:
|
||||
|
||||
server_info->status = DNS_SERVER_STATUS_INIT;
|
||||
|
||||
if (fd > 0) {
|
||||
if (fd > 0 && proxy == NULL) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
proxy_conn_free(proxy);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1825,22 +1930,35 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
int fd = 0;
|
||||
struct epoll_event event;
|
||||
SSL *ssl = NULL;
|
||||
struct proxy_conn *proxy = NULL;
|
||||
|
||||
int yes = 1;
|
||||
const int priority = SOCKET_PRIORITY;
|
||||
const int ip_tos = SOCKET_IP_TOS;
|
||||
int ret = -1;
|
||||
|
||||
if (server_info->ssl_ctx == NULL) {
|
||||
tlog(TLOG_ERROR, "create ssl ctx failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (server_info->proxy_name[0] != '\0') {
|
||||
proxy = proxy_conn_new(server_info->proxy_name, server_info->ip, server_info->port, 0);
|
||||
if (proxy == NULL) {
|
||||
tlog(TLOG_ERROR, "create proxy failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
fd = proxy_conn_get_fd(proxy);
|
||||
} else {
|
||||
fd = socket(server_info->ai_family, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
ssl = SSL_new(server_info->ssl_ctx);
|
||||
if (ssl == NULL) {
|
||||
tlog(TLOG_ERROR, "new ssl failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
fd = socket(server_info->ai_family, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "create socket failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
@@ -1870,8 +1988,14 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority));
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos));
|
||||
|
||||
if (connect(fd, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (errno == ENETUNREACH || errno == EHOSTUNREACH) {
|
||||
if (proxy) {
|
||||
ret = proxy_conn_connect(proxy);
|
||||
} else {
|
||||
ret = connect(fd, &server_info->addr, server_info->ai_addrlen);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
@@ -1902,6 +2026,7 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
server_info->ssl = ssl;
|
||||
server_info->ssl_write_len = -1;
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||
server_info->proxy = proxy;
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLOUT;
|
||||
@@ -1925,7 +2050,7 @@ errout:
|
||||
|
||||
server_info->status = DNS_SERVER_STATUS_INIT;
|
||||
|
||||
if (fd > 0) {
|
||||
if (fd > 0 && proxy == NULL) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
@@ -1933,6 +2058,10 @@ errout:
|
||||
SSL_free(ssl);
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
proxy_conn_free(proxy);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1964,6 +2093,103 @@ static int _dns_client_create_socket(struct dns_server_info *server_info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_process_send_udp_buffer(struct dns_server_info *server_info, struct epoll_event *event,
|
||||
unsigned long now)
|
||||
{
|
||||
int send_len = 0;
|
||||
if (server_info->send_buff.len <= 0 || server_info->status != DNS_SERVER_STATUS_CONNECTED) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (server_info->send_buff.len - send_len > 0) {
|
||||
int ret = 0;
|
||||
int packet_len = 0;
|
||||
packet_len = *(int *)(server_info->send_buff.data + send_len);
|
||||
send_len += sizeof(packet_len);
|
||||
if (packet_len > server_info->send_buff.len - 1) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = _dns_client_send_udp(server_info, server_info->send_buff.data + send_len, packet_len);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "sendto failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
send_len += packet_len;
|
||||
}
|
||||
|
||||
server_info->send_buff.len -= send_len;
|
||||
if (server_info->send_buff.len < 0) {
|
||||
server_info->send_buff.len = 0;
|
||||
}
|
||||
|
||||
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_udp_proxy(struct dns_server_info *server_info, struct epoll_event *event,
|
||||
unsigned long now)
|
||||
{
|
||||
struct sockaddr_storage from;
|
||||
socklen_t from_len = sizeof(from);
|
||||
char from_host[DNS_MAX_CNAME_LEN];
|
||||
unsigned char inpacket[DNS_IN_PACKSIZE];
|
||||
int len = 0;
|
||||
int ret = 0;
|
||||
|
||||
_dns_client_process_send_udp_buffer(server_info, event, now);
|
||||
|
||||
if (!(event->events & EPOLLIN)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = proxy_conn_recvfrom(server_info->proxy, inpacket, sizeof(inpacket), 0, (struct sockaddr *)&from, &from_len);
|
||||
if (len < 0) {
|
||||
tlog(TLOG_ERROR, "recvfrom failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
} else 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, %s", server_info->ip);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d",
|
||||
gethost_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len);
|
||||
|
||||
/* update recv time */
|
||||
time(&server_info->last_recv);
|
||||
|
||||
/* processing dns packet */
|
||||
if (_dns_client_recv(server_info, inpacket, len, (struct sockaddr *)&from, from_len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
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_udp(struct dns_server_info *server_info, struct epoll_event *event, unsigned long now)
|
||||
{
|
||||
int len = 0;
|
||||
@@ -1977,6 +2203,10 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
|
||||
int ttl = 0;
|
||||
struct cmsghdr *cmsg = NULL;
|
||||
|
||||
if (server_info->proxy) {
|
||||
return _dns_client_process_udp_proxy(server_info, event, now);
|
||||
}
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
iov.iov_base = (char *)inpacket;
|
||||
iov.iov_len = sizeof(inpacket);
|
||||
@@ -2685,8 +2915,82 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_proxy_handshake(struct dns_server_info *server_info, struct epoll_event *event, unsigned long now)
|
||||
{
|
||||
struct epoll_event fd_event;
|
||||
proxy_handshake_state ret = proxy_conn_handshake(server_info->proxy);
|
||||
int fd = server_info->fd;
|
||||
int retval = -1;
|
||||
int epoll_op = EPOLL_CTL_MOD;
|
||||
|
||||
if (ret == PROXY_HANDSHAKE_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret == PROXY_HANDSHAKE_ERR) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memset(&fd_event, 0, sizeof(fd_event));
|
||||
if (ret == PROXY_HANDSHAKE_CONNECTED) {
|
||||
fd_event.events = EPOLLIN;
|
||||
if (server_info->type == DNS_SERVER_UDP) {
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTED;
|
||||
epoll_ctl(client.epoll_fd, EPOLL_CTL_DEL, fd, NULL);
|
||||
event->events = 0;
|
||||
fd = proxy_conn_get_udpfd(server_info->proxy);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "get udp fd failed");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
set_fd_nonblock(fd, 1);
|
||||
if (server_info->so_mark >= 0) {
|
||||
unsigned int so_mark = server_info->so_mark;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) != 0) {
|
||||
tlog(TLOG_DEBUG, "set socket mark failed, %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
server_info->fd = fd;
|
||||
epoll_op = EPOLL_CTL_ADD;
|
||||
} else {
|
||||
fd_event.events |= EPOLLOUT;
|
||||
}
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
if (ret == PROXY_HANDSHAKE_WANT_READ) {
|
||||
fd_event.events = EPOLLIN;
|
||||
} else if (ret == PROXY_HANDSHAKE_WANT_WRITE) {
|
||||
fd_event.events = EPOLLOUT | EPOLLIN;
|
||||
}
|
||||
|
||||
fd_event.data.ptr = server_info;
|
||||
if (epoll_ctl(client.epoll_fd, epoll_op, fd, &fd_event) != 0) {
|
||||
tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
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)
|
||||
{
|
||||
if (server_info->proxy) {
|
||||
int ret = _dns_proxy_handshake(server_info, event, now);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (server_info->type == DNS_SERVER_UDP) {
|
||||
/* receive from udp */
|
||||
return _dns_client_process_udp(server_info, event, now);
|
||||
@@ -2703,19 +3007,68 @@ static int _dns_client_process(struct dns_server_info *server_info, struct epoll
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_copy_data_to_buffer(struct dns_server_info *server_info, void *packet, int len)
|
||||
{
|
||||
if (DNS_TCP_BUFFER - server_info->send_buff.len < len) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(server_info->send_buff.data + server_info->send_buff.len, packet, len);
|
||||
server_info->send_buff.len += len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len)
|
||||
{
|
||||
int send_len = 0;
|
||||
const struct sockaddr *addr = &server_info->addr;
|
||||
socklen_t addrlen = server_info->ai_addrlen;
|
||||
int ret = 0;
|
||||
|
||||
if (server_info->fd <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (server_info->proxy) {
|
||||
if (server_info->status != DNS_SERVER_STATUS_CONNECTED) {
|
||||
/*set packet len*/
|
||||
_dns_client_copy_data_to_buffer(server_info, &len, sizeof(len));
|
||||
return _dns_client_copy_data_to_buffer(server_info, packet, len);
|
||||
}
|
||||
|
||||
send_len = proxy_conn_sendto(server_info->proxy, packet, len, 0, addr, addrlen);
|
||||
if (send_len != len) {
|
||||
_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;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_dns_client_copy_data_to_buffer(server_info, &len, sizeof(len));
|
||||
return _dns_client_copy_data_to_buffer(server_info, packet, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
send_len = sendto(server_info->fd, packet, len, 0, NULL, 0);
|
||||
if (send_len != len) {
|
||||
return -1;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_client_send_data_to_buffer(struct dns_server_info *server_info, void *packet, int len)
|
||||
|
||||
@@ -80,8 +80,8 @@ struct dns_query_options {
|
||||
};
|
||||
|
||||
/* query domain */
|
||||
int dns_client_query(const char *domain, int qtype, dns_client_callback callback, void *user_ptr, const char *group_name,
|
||||
struct dns_query_options *options);
|
||||
int dns_client_query(const char *domain, int qtype, dns_client_callback callback, void *user_ptr,
|
||||
const char *group_name, struct dns_query_options *options);
|
||||
|
||||
void dns_client_exit(void);
|
||||
|
||||
@@ -102,6 +102,7 @@ struct client_dns_server_flag_https {
|
||||
int spi_len;
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
char httphost[DNS_MAX_CNAME_LEN];
|
||||
char proxyname[DNS_MAX_CNAME_LEN];
|
||||
char path[DNS_MAX_CNAME_LEN];
|
||||
char tls_host_verify[DNS_MAX_CNAME_LEN];
|
||||
char skip_check_cert;
|
||||
@@ -112,7 +113,7 @@ struct client_dns_server_flags {
|
||||
unsigned int server_flag;
|
||||
unsigned int result_flag;
|
||||
long long set_mark;
|
||||
|
||||
char proxyname[DNS_MAX_CNAME_LEN];
|
||||
union {
|
||||
struct client_dns_server_flag_udp udp;
|
||||
struct client_dns_server_flag_tls tls;
|
||||
|
||||
250
src/dns_conf.c
250
src/dns_conf.c
@@ -1,6 +1,6 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -52,6 +52,7 @@ struct dns_domain_set_name_table dns_domain_set_name_table;
|
||||
|
||||
/* dns groups */
|
||||
struct dns_group_table dns_group_table;
|
||||
struct dns_proxy_table dns_proxy_table;
|
||||
|
||||
struct dns_ptr_table dns_ptr_table;
|
||||
|
||||
@@ -100,6 +101,10 @@ struct dns_domain_check_orders dns_conf_check_orders = {
|
||||
};
|
||||
static int dns_has_cap_ping = 0;
|
||||
|
||||
/* proxy servers */
|
||||
struct dns_proxy_servers dns_conf_proxy_servers[PROXY_MAX_SERVERS];
|
||||
int dns_conf_proxy_server_num;
|
||||
|
||||
/* logging */
|
||||
int dns_conf_log_level = TLOG_ERROR;
|
||||
char dns_conf_log_file[DNS_MAX_PATH];
|
||||
@@ -345,6 +350,101 @@ static void _config_group_table_destroy(void)
|
||||
}
|
||||
}
|
||||
|
||||
struct dns_proxy_names *dns_server_get_proxy_nams(const char *proxyname)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_proxy_names *proxy = NULL;
|
||||
|
||||
key = hash_string(proxyname);
|
||||
hash_for_each_possible(dns_proxy_table.proxy, proxy, node, key)
|
||||
{
|
||||
if (strncmp(proxy->proxy_name, proxyname, DNS_MAX_IPLEN) == 0) {
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create and get dns server group */
|
||||
static struct dns_proxy_names *_dns_conf_get_proxy(const char *proxy_name)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_proxy_names *proxy = NULL;
|
||||
|
||||
key = hash_string(proxy_name);
|
||||
hash_for_each_possible(dns_proxy_table.proxy, proxy, node, key)
|
||||
{
|
||||
if (strncmp(proxy->proxy_name, proxy_name, DNS_MAX_IPLEN) == 0) {
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
|
||||
proxy = malloc(sizeof(*proxy));
|
||||
if (proxy == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memset(proxy, 0, sizeof(*proxy));
|
||||
safe_strncpy(proxy->proxy_name, proxy_name, PROXY_NAME_LEN);
|
||||
hash_add(dns_proxy_table.proxy, &proxy->node, key);
|
||||
INIT_LIST_HEAD(&proxy->server_list);
|
||||
|
||||
return proxy;
|
||||
errout:
|
||||
if (proxy) {
|
||||
free(proxy);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _dns_conf_proxy_servers_add(const char *proxy_name, struct dns_proxy_servers *server)
|
||||
{
|
||||
struct dns_proxy_names *proxy = NULL;
|
||||
|
||||
proxy = _dns_conf_get_proxy(proxy_name);
|
||||
if (proxy == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_add_tail(&server->list, &proxy->server_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *_dns_conf_get_proxy_name(const char *proxy_name)
|
||||
{
|
||||
struct dns_proxy_names *proxy = NULL;
|
||||
|
||||
proxy = _dns_conf_get_proxy(proxy_name);
|
||||
if (proxy == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return proxy->proxy_name;
|
||||
}
|
||||
|
||||
static void _config_proxy_table_destroy(void)
|
||||
{
|
||||
struct dns_proxy_names *proxy = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
unsigned int i;
|
||||
struct dns_proxy_servers *server = NULL;
|
||||
struct dns_proxy_servers *server_tmp = NULL;
|
||||
|
||||
hash_for_each_safe(dns_proxy_table.proxy, i, tmp, proxy, node)
|
||||
{
|
||||
hlist_del_init(&proxy->node);
|
||||
list_for_each_entry_safe(server, server_tmp, &proxy->server_list, list)
|
||||
{
|
||||
list_del(&server->list);
|
||||
free(server);
|
||||
}
|
||||
free(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
static int _config_server(int argc, char *argv[], dns_server_type_t type, int default_port)
|
||||
{
|
||||
int index = dns_conf_server_num;
|
||||
@@ -371,6 +471,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
{"no-check-certificate", no_argument, NULL, 'N'}, /* do not check certificate */
|
||||
{"tls-host-verify", required_argument, NULL, 'V' }, /* verify tls hostname */
|
||||
{"group", required_argument, NULL, 'g'}, /* add to group */
|
||||
{"proxy", required_argument, NULL, 'P'}, /* proxy server */
|
||||
{"exclude-default-group", no_argument, NULL, 'E'}, /* ecluse this from default group */
|
||||
{"set-mark", required_argument, NULL, 254}, /* set mark */
|
||||
{NULL, no_argument, NULL, 0}
|
||||
@@ -393,6 +494,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
server->hostname[0] = '\0';
|
||||
server->httphost[0] = '\0';
|
||||
server->tls_host_verify[0] = '\0';
|
||||
server->proxyname[0] = '\0';
|
||||
server->set_mark = -1;
|
||||
|
||||
if (type == DNS_SERVER_HTTPS) {
|
||||
@@ -463,6 +565,14 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
safe_strncpy(server->spki, optarg, DNS_MAX_SPKI_LEN);
|
||||
break;
|
||||
}
|
||||
case 'P': {
|
||||
if (_dns_conf_get_proxy_name(optarg) == NULL) {
|
||||
tlog(TLOG_ERROR, "add proxy server failed.");
|
||||
goto errout;
|
||||
}
|
||||
safe_strncpy(server->proxyname, optarg, PROXY_NAME_LEN);
|
||||
break;
|
||||
}
|
||||
case 'V': {
|
||||
safe_strncpy(server->tls_host_verify, optarg, DNS_MAX_CNAME_LEN);
|
||||
break;
|
||||
@@ -1489,6 +1599,141 @@ errout:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _config_proxy_server(int argc, char *argv[], struct dns_proxy_servers **pserver, proxy_type_t type)
|
||||
{
|
||||
int index = dns_conf_proxy_server_num;
|
||||
struct dns_proxy_servers *server = NULL;
|
||||
char *servers_name = NULL;
|
||||
int port = -1;
|
||||
char *ip = NULL;
|
||||
int opt = 0;
|
||||
unsigned int server_flag = 0;
|
||||
int use_domain = 0;
|
||||
|
||||
/* clang-format off */
|
||||
static struct option long_options[] = {
|
||||
{"name", required_argument, NULL, 'n'},
|
||||
{"use-domain", no_argument, NULL, 'd'},
|
||||
{"user", required_argument, NULL, 'u'},
|
||||
{"password", required_argument, NULL, 'p'},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
};
|
||||
/* clang-format on */
|
||||
if (argc <= 1) {
|
||||
tlog(TLOG_ERROR, "invalid parameter.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip = argv[1];
|
||||
if (index >= PROXY_MAX_SERVERS) {
|
||||
tlog(TLOG_WARN, "exceeds max server number, %s", ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
server = malloc(sizeof(*server));
|
||||
if (server == NULL) {
|
||||
tlog(TLOG_WARN, "malloc memory failed.");
|
||||
return -1;
|
||||
}
|
||||
memset(server, 0, sizeof(*server));
|
||||
|
||||
/* process extra options */
|
||||
optind = 1;
|
||||
while (1) {
|
||||
opt = getopt_long_only(argc, argv, "n:du:p:", long_options, NULL);
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (opt) {
|
||||
case 'n': {
|
||||
servers_name = optarg;
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
use_domain = 1;
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
safe_strncpy(server->username, optarg, sizeof(server->username));
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
safe_strncpy(server->password, optarg, sizeof(server->password));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ip = argv[optind];
|
||||
if (ip) {
|
||||
/* parse ip, port from ip */
|
||||
if (parse_ip(ip, server->server, &port) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if port is not defined, set port to default 53 */
|
||||
if (port == PORT_NOT_DEFINED) {
|
||||
port = 443;
|
||||
}
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (servers_name == NULL) {
|
||||
tlog(TLOG_ERROR, "please set name");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_conf_proxy_servers_add(servers_name, server) != 0) {
|
||||
tlog(TLOG_ERROR, "add group failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* add new server */
|
||||
server->type = type;
|
||||
server->port = port;
|
||||
server->server_flag = server_flag;
|
||||
server->use_domain = use_domain;
|
||||
dns_conf_proxy_server_num++;
|
||||
tlog(TLOG_DEBUG, "add proxy server %s, flag: %X", ip, server_flag);
|
||||
|
||||
if (pserver) {
|
||||
*pserver = server;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (server) {
|
||||
free(server);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _config_proxy_socks5(void *data, int argc, char *argv[])
|
||||
{
|
||||
struct dns_proxy_servers *server = NULL;
|
||||
int ret = _config_proxy_server(argc, argv, &server, PROXY_SOCKS5);
|
||||
if (ret == 0) {
|
||||
server->socks5 = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _config_proxy_http(void *data, int argc, char *argv[])
|
||||
{
|
||||
struct dns_proxy_servers *server = NULL;
|
||||
int ret = _config_proxy_server(argc, argv, &server, PROXY_HTTP);
|
||||
if (ret == 0) {
|
||||
server->https = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static radix_node_t *_create_addr_node(char *addr)
|
||||
{
|
||||
radix_node_t *node = NULL;
|
||||
@@ -2400,6 +2645,8 @@ static struct config_item _config_item[] = {
|
||||
CONF_CUSTOM("server-https", _config_server_https, NULL),
|
||||
CONF_CUSTOM("nameserver", _config_nameserver, NULL),
|
||||
CONF_CUSTOM("address", _config_address, NULL),
|
||||
CONF_CUSTOM("proxy-socks5", _config_proxy_socks5, NULL),
|
||||
CONF_CUSTOM("proxy-http", _config_proxy_http, NULL),
|
||||
CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable),
|
||||
CONF_CUSTOM("ipset", _config_ipset, NULL),
|
||||
CONF_YESNO("nftset-timeout", &dns_conf_nftset_timeout_enable),
|
||||
@@ -2635,6 +2882,7 @@ void dns_server_load_exit(void)
|
||||
_config_ptr_table_destroy();
|
||||
_config_host_table_destroy();
|
||||
_config_qtype_soa_table_destroy();
|
||||
_config_proxy_table_destroy();
|
||||
}
|
||||
|
||||
static int _dns_conf_speed_check_mode_verify(void)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "hash.h"
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "proxy.h"
|
||||
#include "radix.h"
|
||||
|
||||
#ifdef __cpluscplus
|
||||
@@ -41,8 +42,13 @@ extern "C" {
|
||||
#define DNS_MAX_NFTSET_FAMILYLEN 8
|
||||
#define DNS_MAX_NFTSET_NAMELEN 256
|
||||
#define DNS_GROUP_NAME_LEN 32
|
||||
|
||||
#define PROXY_NAME_LEN 32
|
||||
#define PROXY_MAX_SERVERS 128
|
||||
|
||||
#define DNS_NAX_GROUP_NUMBER 16
|
||||
#define DNS_MAX_IPLEN 64
|
||||
#define DNS_PROXY_MAX_LEN 128
|
||||
#define DNS_CONF_USRNAME_LEN 32
|
||||
#define DNS_MAX_SPKI_LEN 64
|
||||
#define DNS_MAX_URL_LEN 256
|
||||
@@ -224,6 +230,17 @@ struct dns_hosts_table {
|
||||
extern struct dns_hosts_table dns_hosts_table;
|
||||
extern int dns_hosts_record_num;
|
||||
|
||||
struct dns_proxy_names {
|
||||
struct hlist_node node;
|
||||
char proxy_name[PROXY_NAME_LEN];
|
||||
struct list_head server_list;
|
||||
};
|
||||
|
||||
struct dns_proxy_table {
|
||||
DECLARE_HASHTABLE(proxy, 4);
|
||||
};
|
||||
extern struct dns_proxy_table dns_proxy_table;
|
||||
|
||||
struct dns_servers {
|
||||
char server[DNS_MAX_IPLEN];
|
||||
unsigned short port;
|
||||
@@ -238,6 +255,21 @@ struct dns_servers {
|
||||
char httphost[DNS_MAX_CNAME_LEN];
|
||||
char tls_host_verify[DNS_MAX_CNAME_LEN];
|
||||
char path[DNS_MAX_URL_LEN];
|
||||
char proxyname[PROXY_NAME_LEN];
|
||||
};
|
||||
|
||||
struct dns_proxy_servers {
|
||||
struct list_head list;
|
||||
char server[DNS_MAX_IPLEN];
|
||||
proxy_type_t type;
|
||||
unsigned short port;
|
||||
unsigned int server_flag;
|
||||
char username[DNS_PROXY_MAX_LEN];
|
||||
char password[DNS_PROXY_MAX_LEN];
|
||||
|
||||
int socks5;
|
||||
int https;
|
||||
int use_domain;
|
||||
};
|
||||
|
||||
/* ip address lists of domain */
|
||||
@@ -346,11 +378,15 @@ extern int dns_conf_serve_expired_reply_ttl;
|
||||
extern struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
extern int dns_conf_server_num;
|
||||
|
||||
/* proxy servers */
|
||||
extern struct dns_proxy_servers dns_conf_proxy_servers[PROXY_MAX_SERVERS];
|
||||
extern int dns_conf_proxy_server_num;
|
||||
|
||||
extern int dns_conf_log_level;
|
||||
extern char dns_conf_log_file[DNS_MAX_PATH];
|
||||
extern size_t dns_conf_log_size;
|
||||
extern int dns_conf_log_num;
|
||||
extern int dns_conf_log_file_mode;;
|
||||
extern int dns_conf_log_file_mode;
|
||||
|
||||
extern char dns_conf_ca_file[DNS_MAX_PATH];
|
||||
extern char dns_conf_ca_path[DNS_MAX_PATH];
|
||||
@@ -415,6 +451,8 @@ int dns_server_load_conf(const char *file);
|
||||
|
||||
int dns_server_check_update_hosts(void);
|
||||
|
||||
struct dns_proxy_names *dns_server_get_proxy_nams(const char *proxyname);
|
||||
|
||||
extern int config_addtional_file(void *data, int argc, char *argv[]);
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -805,7 +805,7 @@ static int _dns_add_rrs(struct dns_server_post_context *context)
|
||||
}
|
||||
|
||||
if (request->rcode != DNS_RC_NOERROR) {
|
||||
tlog(TLOG_INFO, "result %s, qtype: %d, rtcode: %d", domain, context->qtype, request->rcode);
|
||||
tlog(TLOG_INFO, "result: %s, qtype: %d, rtcode: %d", domain, context->qtype, request->rcode);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
993
src/proxy.c
Normal file
993
src/proxy.c
Normal file
@@ -0,0 +1,993 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
#include "proxy.h"
|
||||
#include "dns_conf.h"
|
||||
#include "hashtable.h"
|
||||
#include "http_parse.h"
|
||||
#include "list.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#define PROXY_SOCKS5_VERSION 0x05
|
||||
#define PROXY_SOCKS5_NO_AUTH 0x00
|
||||
#define PROXY_SOCKS5_AUTH_USER_PASS 0x02
|
||||
#define PROXY_SOCKS5_AUTH_NONE 0xFF
|
||||
|
||||
#define PROXY_SOCKS5_TYPE_IPV4 0x01
|
||||
#define PROXY_SOCKS5_TYPE_DOMAIN 0x03
|
||||
#define PROXY_SOCKS5_TYPE_IPV6 0x04
|
||||
|
||||
#define PROXY_SOCKS5_CONNECT_TCP 0x01
|
||||
#define PROXY_SOCKS5_CONNECT_UDP 0x03
|
||||
|
||||
#define PROXY_MAX_EVENTS 64
|
||||
#define PROXY_BUFFER_SIZE (1024 * 8)
|
||||
#define PROXY_MAX_HOSTNAME_LEN 256
|
||||
|
||||
typedef enum PROXY_CONN_STATE {
|
||||
PROXY_CONN_INIT = 0,
|
||||
PROXY_CONN_INIT_ACK = 1,
|
||||
PROXY_CONN_AUTH = 2,
|
||||
PROXY_CONN_AUTH_ACK = 3,
|
||||
PROXY_CONN_CONNECTING = 4,
|
||||
PROXY_CONN_CONNECTED = 5,
|
||||
} PROXY_CONN_STATE;
|
||||
|
||||
struct proxy_conn {
|
||||
proxy_type_t type;
|
||||
PROXY_CONN_STATE state;
|
||||
char host[DNS_MAX_CNAME_LEN];
|
||||
unsigned short port;
|
||||
int fd;
|
||||
int udp_fd;
|
||||
int buffer_len;
|
||||
int is_udp;
|
||||
struct sockaddr_storage udp_dest_addr;
|
||||
socklen_t udp_dest_addrlen;
|
||||
struct proxy_server_info *server_info;
|
||||
};
|
||||
|
||||
/* upstream server groups */
|
||||
struct proxy_server_info {
|
||||
struct hlist_node node;
|
||||
char proxy_name[PROXY_NAME_LEN];
|
||||
struct sockaddr_storage server_addr;
|
||||
socklen_t server_addrlen;
|
||||
struct proxy_info info;
|
||||
};
|
||||
|
||||
struct proxy_struct {
|
||||
int run;
|
||||
int epoll_fd;
|
||||
pthread_t tid;
|
||||
pthread_mutex_t proxy_lock;
|
||||
DECLARE_HASHTABLE(proxy_server, 4);
|
||||
};
|
||||
|
||||
static struct proxy_struct proxy;
|
||||
|
||||
const char *proxy_socks5_status_code[] = {
|
||||
"success",
|
||||
"general SOCKS server failure",
|
||||
"connection not allowed by ruleset",
|
||||
"Network unreachable",
|
||||
"Host unreachable",
|
||||
"Connection refused",
|
||||
"TTL expired",
|
||||
"Command not supported",
|
||||
"Address type not supported",
|
||||
};
|
||||
|
||||
/* get server group by name */
|
||||
static struct proxy_server_info *_proxy_get_server_info(const char *proxy_name)
|
||||
{
|
||||
unsigned long key;
|
||||
struct proxy_server_info *server_info = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
|
||||
if (proxy_name == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = hash_string(proxy_name);
|
||||
hash_for_each_possible_safe(proxy.proxy_server, server_info, tmp, node, key)
|
||||
{
|
||||
if (strncmp(server_info->proxy_name, proxy_name, DNS_GROUP_NAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return server_info;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct addrinfo *_proxy_getaddr(const char *host, int port, int type, int protocol)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result = NULL;
|
||||
int ret = 0;
|
||||
char port_str[32];
|
||||
|
||||
snprintf(port_str, sizeof(port_str), "%d", port);
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = type;
|
||||
hints.ai_protocol = protocol;
|
||||
|
||||
ret = getaddrinfo(host, port_str, &hints, &result);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "get addr info failed. %s\n", gai_strerror(ret));
|
||||
tlog(TLOG_ERROR, "host = %s, port = %d, type = %d, protocol = %d", host, port, type, protocol);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return result;
|
||||
errout:
|
||||
if (result) {
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int proxy_add(const char *proxy_name, struct proxy_info *info)
|
||||
{
|
||||
unsigned long key;
|
||||
char ip_str[PROXY_MAX_IPLEN];
|
||||
int port = 0;
|
||||
struct addrinfo *gai = NULL;
|
||||
struct proxy_server_info *server_info = _proxy_get_server_info(proxy_name);
|
||||
|
||||
if (server_info) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
server_info = malloc(sizeof(*server_info));
|
||||
if (server_info == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memset(server_info, 0, sizeof(*server_info));
|
||||
memcpy(&server_info->info, info, sizeof(struct proxy_info));
|
||||
|
||||
if (parse_ip(info->server, ip_str, &port) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
port = info->port;
|
||||
gai = _proxy_getaddr(info->server, port, SOCK_STREAM, 0);
|
||||
if (gai == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
server_info->server_addrlen = gai->ai_addrlen;
|
||||
memcpy(&server_info->server_addr, gai->ai_addr, gai->ai_addrlen);
|
||||
|
||||
safe_strncpy(server_info->proxy_name, proxy_name, PROXY_NAME_LEN);
|
||||
key = hash_string(server_info->proxy_name);
|
||||
hash_add(proxy.proxy_server, &server_info->node, key);
|
||||
|
||||
freeaddrinfo(gai);
|
||||
return 0;
|
||||
errout:
|
||||
if (server_info) {
|
||||
free(server_info);
|
||||
server_info = NULL;
|
||||
}
|
||||
|
||||
if (gai) {
|
||||
freeaddrinfo(gai);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _proxy_remove(struct proxy_server_info *server_info)
|
||||
{
|
||||
hash_del(&server_info->node);
|
||||
free(server_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_remove(const char *proxy_name)
|
||||
{
|
||||
struct proxy_server_info *server_info = _proxy_get_server_info(proxy_name);
|
||||
if (server_info == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_proxy_remove(server_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _proxy_remove_all(void)
|
||||
{
|
||||
struct proxy_server_info *server_info;
|
||||
struct hlist_node *tmp = NULL;
|
||||
unsigned int i = 0;
|
||||
|
||||
hash_for_each_safe(proxy.proxy_server, i, tmp, server_info, node)
|
||||
{
|
||||
_proxy_remove(server_info);
|
||||
}
|
||||
}
|
||||
|
||||
struct proxy_conn *proxy_conn_new(const char *proxy_name, const char *host, int port, int is_udp)
|
||||
{
|
||||
struct proxy_conn *proxy_conn = NULL;
|
||||
struct proxy_server_info *server_info = NULL;
|
||||
struct addrinfo *gai = NULL;
|
||||
int fd = -1;
|
||||
|
||||
server_info = _proxy_get_server_info(proxy_name);
|
||||
if (server_info == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (is_udp == 1 && server_info->info.type != PROXY_SOCKS5) {
|
||||
tlog(TLOG_WARN, "only socks5 support udp");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
fd = socket(server_info->server_addr.ss_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||
if (fd < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
proxy_conn = malloc(sizeof(*proxy_conn));
|
||||
if (proxy_conn == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memset(proxy_conn, 0, sizeof(*proxy_conn));
|
||||
safe_strncpy(proxy_conn->host, host, DNS_MAX_CNAME_LEN);
|
||||
proxy_conn->port = port;
|
||||
proxy_conn->type = server_info->info.type;
|
||||
proxy_conn->state = PROXY_CONN_INIT;
|
||||
proxy_conn->server_info = server_info;
|
||||
proxy_conn->fd = fd;
|
||||
proxy_conn->udp_fd = -1;
|
||||
proxy_conn->is_udp = is_udp;
|
||||
|
||||
return proxy_conn;
|
||||
errout:
|
||||
if (proxy_conn) {
|
||||
free(proxy_conn);
|
||||
proxy_conn = NULL;
|
||||
}
|
||||
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (gai) {
|
||||
freeaddrinfo(gai);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void proxy_conn_free(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
if (proxy_conn == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (proxy_conn->fd >= 0) {
|
||||
close(proxy_conn->fd);
|
||||
}
|
||||
|
||||
if (proxy_conn->udp_fd >= 0) {
|
||||
close(proxy_conn->udp_fd);
|
||||
}
|
||||
|
||||
free(proxy_conn);
|
||||
}
|
||||
|
||||
int proxy_conn_connect(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
if (proxy_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return connect(proxy_conn->fd, (struct sockaddr *)&proxy_conn->server_info->server_addr,
|
||||
proxy_conn->server_info->server_addrlen);
|
||||
}
|
||||
|
||||
static int _proxy_handshake_socks5_create_udp_fd(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
int ret = 0;
|
||||
char *gai_host = NULL;
|
||||
int udp_fd = -1;
|
||||
struct addrinfo *gai = NULL;
|
||||
|
||||
switch (proxy_conn->udp_dest_addr.ss_family) {
|
||||
case AF_INET:
|
||||
gai_host = "0.0.0.0";
|
||||
break;
|
||||
case AF_INET6:
|
||||
gai_host = "::";
|
||||
break;
|
||||
default:
|
||||
goto errout;
|
||||
break;
|
||||
}
|
||||
|
||||
gai = _proxy_getaddr(gai_host, 0, SOCK_DGRAM, 0);
|
||||
udp_fd = socket(gai->ai_family, gai->ai_socktype | SOCK_CLOEXEC, 0);
|
||||
if (udp_fd < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = bind(udp_fd, gai->ai_addr, gai->ai_addrlen);
|
||||
if (ret < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
freeaddrinfo(gai);
|
||||
return udp_fd;
|
||||
errout:
|
||||
if (gai) {
|
||||
freeaddrinfo(gai);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _proxy_handshake_socks5_connect_udp(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
int udp_fd = -1;
|
||||
|
||||
if (proxy_conn->is_udp == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (proxy_conn->udp_fd < 0) {
|
||||
udp_fd = _proxy_handshake_socks5_create_udp_fd(proxy_conn);
|
||||
if (udp_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
proxy_conn->udp_fd = udp_fd;
|
||||
}
|
||||
|
||||
return connect(proxy_conn->udp_fd, (struct sockaddr *)&proxy_conn->udp_dest_addr, proxy_conn->udp_dest_addrlen);
|
||||
}
|
||||
|
||||
static proxy_handshake_state _proxy_handshake_socks5_reply_connect_addr(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
char buff[DNS_MAX_CNAME_LEN * 2];
|
||||
int len = 0;
|
||||
memset(buff, 0, sizeof(buff));
|
||||
struct sockaddr_storage addr;
|
||||
char *ptr = buff;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
|
||||
buff[0] = PROXY_SOCKS5_VERSION;
|
||||
if (proxy_conn->is_udp) {
|
||||
buff[1] = PROXY_SOCKS5_CONNECT_UDP;
|
||||
} else {
|
||||
buff[1] = PROXY_SOCKS5_CONNECT_TCP;
|
||||
}
|
||||
|
||||
buff[2] = 0x0;
|
||||
ptr = buff + 3;
|
||||
if (proxy_conn->server_info->info.use_domain) {
|
||||
*ptr = PROXY_SOCKS5_TYPE_DOMAIN;
|
||||
ptr++;
|
||||
|
||||
int domainlen = strnlen(proxy_conn->host, DNS_MAX_CNAME_LEN);
|
||||
*ptr = domainlen;
|
||||
ptr++;
|
||||
memcpy(ptr, proxy_conn->host, domainlen);
|
||||
ptr += domainlen;
|
||||
} else {
|
||||
if (proxy_conn->is_udp) {
|
||||
memset(&addr, 0, proxy_conn->server_info->server_addrlen);
|
||||
addr_len = proxy_conn->server_info->server_addrlen;
|
||||
addr.ss_family = proxy_conn->server_info->server_addr.ss_family;
|
||||
} else {
|
||||
getaddr_by_host(proxy_conn->host, (struct sockaddr *)&addr, &addr_len);
|
||||
}
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in = NULL;
|
||||
addr_in = (struct sockaddr_in *)&addr;
|
||||
*ptr = PROXY_SOCKS5_TYPE_IPV4;
|
||||
ptr++;
|
||||
memcpy(ptr, &addr_in->sin_addr.s_addr, 4);
|
||||
ptr += 4;
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
*ptr = PROXY_SOCKS5_TYPE_IPV4;
|
||||
ptr++;
|
||||
memcpy(ptr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||
ptr += 4;
|
||||
} else {
|
||||
*ptr = PROXY_SOCKS5_TYPE_IPV6;
|
||||
ptr++;
|
||||
memcpy(ptr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
ptr += 16;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
}
|
||||
*((short *)(ptr)) = htons(proxy_conn->port);
|
||||
ptr += 2;
|
||||
|
||||
len = send(proxy_conn->fd, buff, ptr - buff, MSG_NOSIGNAL);
|
||||
if (len != ptr - buff) {
|
||||
tlog(TLOG_ERROR, "Send proxy request failed.");
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
proxy_conn->state = PROXY_CONN_CONNECTING;
|
||||
return PROXY_HANDSHAKE_WANT_READ;
|
||||
}
|
||||
|
||||
static proxy_handshake_state _proxy_handshake_socks5_send_auth(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
char buff[DNS_MAX_CNAME_LEN * 2];
|
||||
int len = 0;
|
||||
int offset = 0;
|
||||
memset(buff, 0, sizeof(buff));
|
||||
|
||||
buff[0] = 0x1;
|
||||
buff[1] = strnlen(proxy_conn->server_info->info.username, PROXY_MAX_NAMELEN);
|
||||
safe_strncpy(buff + 2, proxy_conn->server_info->info.username, buff[1] + 1);
|
||||
offset = buff[1] + 2;
|
||||
buff[offset] = strnlen(proxy_conn->server_info->info.password, PROXY_MAX_NAMELEN);
|
||||
safe_strncpy(buff + offset + 1, proxy_conn->server_info->info.password, buff[offset] + 1);
|
||||
offset += buff[offset] + 1;
|
||||
len = send(proxy_conn->fd, buff, offset, MSG_NOSIGNAL);
|
||||
if (len != offset) {
|
||||
tlog(TLOG_ERROR, "send auth failed, len = %d, errno = %s", len, strerror(errno));
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
proxy_conn->state = PROXY_CONN_AUTH_ACK;
|
||||
return PROXY_HANDSHAKE_WANT_READ;
|
||||
}
|
||||
|
||||
static proxy_handshake_state _proxy_handshake_socks5(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
int len = 0;
|
||||
char buff[DNS_MAX_CNAME_LEN * 2];
|
||||
memset(buff, 0, sizeof(buff));
|
||||
|
||||
switch (proxy_conn->state) {
|
||||
case PROXY_CONN_INIT: {
|
||||
buff[0] = PROXY_SOCKS5_VERSION;
|
||||
buff[1] = 0x2; // 2 auth methods
|
||||
buff[2] = PROXY_SOCKS5_NO_AUTH;
|
||||
buff[3] = PROXY_SOCKS5_AUTH_USER_PASS;
|
||||
len = send(proxy_conn->fd, buff, 4, MSG_NOSIGNAL);
|
||||
if (len != 4) {
|
||||
tlog(TLOG_ERROR, "init socks5 failed, errno = %s", strerror(errno));
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
proxy_conn->state = PROXY_CONN_INIT_ACK;
|
||||
return PROXY_HANDSHAKE_WANT_READ;
|
||||
} break;
|
||||
case PROXY_CONN_INIT_ACK:
|
||||
len = recv(proxy_conn->fd, buff, sizeof(buff), 0);
|
||||
if (len <= 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return PROXY_HANDSHAKE_WANT_READ;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "recv socks5 init ack failed, errno = %s", strerror(errno));
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (len != 2) {
|
||||
tlog(TLOG_ERROR, "recv socks5 init ack failed, len = %d", len);
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (buff[0] != PROXY_SOCKS5_VERSION) {
|
||||
tlog(TLOG_ERROR, "Server not support socks5");
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if ((unsigned char)buff[1] == PROXY_SOCKS5_AUTH_NONE) {
|
||||
tlog(TLOG_ERROR, "Server not support auth methods");
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
tlog(TLOG_INFO, "Server select auth method is %d", buff[1]);
|
||||
if (buff[1] == PROXY_SOCKS5_AUTH_USER_PASS) {
|
||||
return _proxy_handshake_socks5_send_auth(proxy_conn);
|
||||
}
|
||||
|
||||
if (buff[1] == PROXY_SOCKS5_NO_AUTH) {
|
||||
return _proxy_handshake_socks5_reply_connect_addr(proxy_conn);
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "Server select invalid auth method %d", buff[1]);
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
break;
|
||||
case PROXY_CONN_AUTH_ACK:
|
||||
len = recv(proxy_conn->fd, buff, sizeof(buff), 0);
|
||||
if (len <= 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return PROXY_HANDSHAKE_WANT_READ;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "recv socks5 auth ack failed, errno = %s", strerror(errno));
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (len != 2) {
|
||||
tlog(TLOG_ERROR, "recv socks5 auth ack failed, len = %d", len);
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (buff[0] != 0x1) {
|
||||
tlog(TLOG_ERROR, "Server not support socks5");
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (buff[1] != 0x0) {
|
||||
tlog(TLOG_ERROR, "Server auth failed, code = %d", buff[1]);
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
tlog(TLOG_INFO, "Server auth success");
|
||||
proxy_conn->state = PROXY_CONN_CONNECTING;
|
||||
return _proxy_handshake_socks5_reply_connect_addr(proxy_conn);
|
||||
case PROXY_CONN_CONNECTING: {
|
||||
unsigned char addr[16];
|
||||
unsigned short port = 0;
|
||||
int use_dest_ip = 0;
|
||||
|
||||
int addr_len = 0;
|
||||
len = recv(proxy_conn->fd, buff, sizeof(buff), 0);
|
||||
if (len <= 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return PROXY_HANDSHAKE_WANT_READ;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "recv socks5 connect ack failed, errno = %s", strerror(errno));
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (len < 10) {
|
||||
tlog(TLOG_ERROR, "Server reply connect addr failed, len = %d", len);
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (buff[0] != PROXY_SOCKS5_VERSION) {
|
||||
tlog(TLOG_ERROR, "Server not support socks5");
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (buff[1] != 0) {
|
||||
if ((unsigned char)buff[1] <= (sizeof(proxy_socks5_status_code) / sizeof(proxy_socks5_status_code[0]))) {
|
||||
tlog(TLOG_ERROR, "Server replay failed, error code %s", proxy_socks5_status_code[(int)buff[1]]);
|
||||
} else {
|
||||
tlog(TLOG_ERROR, "Server replay failed, error code %x", buff[1]);
|
||||
}
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
switch (buff[3]) {
|
||||
case PROXY_SOCKS5_TYPE_IPV4: {
|
||||
struct sockaddr_in *addr_in = NULL;
|
||||
addr_in = (struct sockaddr_in *)&proxy_conn->udp_dest_addr;
|
||||
proxy_conn->udp_dest_addrlen = sizeof(struct sockaddr_in);
|
||||
if (len != 10) {
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
addr_len = 4;
|
||||
memcpy(addr, buff + 4, addr_len);
|
||||
port = ntohs(*((short *)(buff + 4 + addr_len)));
|
||||
addr_in->sin_family = AF_INET;
|
||||
addr_in->sin_addr.s_addr = *((int *)addr);
|
||||
addr_in->sin_port = *((short *)(buff + 4 + addr_len));
|
||||
if (addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0) {
|
||||
use_dest_ip = 1;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "proxy dest: %d.%d.%d.%d:%d\n", addr[0], addr[1], addr[2], addr[3], port);
|
||||
} break;
|
||||
case PROXY_SOCKS5_TYPE_IPV6: {
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)&proxy_conn->udp_dest_addr;
|
||||
proxy_conn->udp_dest_addrlen = sizeof(struct sockaddr_in6);
|
||||
if (len != 22) {
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
addr_len = 16;
|
||||
memcpy(addr, buff + 4, addr_len);
|
||||
port = ntohs(*((short *)(buff + 4 + addr_len)));
|
||||
addr_in6->sin6_family = AF_INET6;
|
||||
memcpy(addr_in6->sin6_addr.s6_addr, addr, addr_len);
|
||||
addr_in6->sin6_port = *((short *)(buff + 4 + addr_len));
|
||||
|
||||
if (addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 && addr[4] == 0 && addr[5] == 0 &&
|
||||
addr[6] == 0 && addr[7] == 0 && addr[8] == 0 && addr[9] == 0 && addr[10] == 0 && addr[11] == 0 &&
|
||||
addr[12] == 0 && addr[13] == 0 && addr[14] == 0 && addr[15] == 0) {
|
||||
use_dest_ip = 1;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "proxy dest: [%x:%x:%x:%x:%x:%x:%x:%x]:%d\n", ntohs(*((short *)addr)),
|
||||
ntohs(*((short *)(addr + 2))), ntohs(*((short *)(addr + 4))), ntohs(*((short *)(addr + 6))),
|
||||
ntohs(*((short *)(addr + 8))), ntohs(*((short *)(addr + 10))), ntohs(*((short *)(addr + 12))),
|
||||
ntohs(*((short *)(addr + 14))), port);
|
||||
} break;
|
||||
default:
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
if (use_dest_ip && proxy_conn->is_udp) {
|
||||
memcpy(&proxy_conn->udp_dest_addr, &proxy_conn->server_info->server_addr,
|
||||
proxy_conn->server_info->server_addrlen);
|
||||
proxy_conn->udp_dest_addrlen = proxy_conn->server_info->server_addrlen;
|
||||
switch (proxy_conn->udp_dest_addr.ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in = NULL;
|
||||
addr_in = (struct sockaddr_in *)&proxy_conn->udp_dest_addr;
|
||||
addr_in->sin_port = *((short *)(buff + 4 + addr_len));
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)&proxy_conn->udp_dest_addr;
|
||||
addr_in6->sin6_port = *((short *)(buff + 4 + addr_len));
|
||||
} break;
|
||||
default:
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_proxy_handshake_socks5_connect_udp(proxy_conn) != 0) {
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
proxy_conn->state = PROXY_CONN_CONNECTED;
|
||||
tlog(TLOG_INFO, "connected to socks proxy server.");
|
||||
return PROXY_HANDSHAKE_CONNECTED;
|
||||
} break;
|
||||
default:
|
||||
tlog(TLOG_ERROR, "client socks status %d is invalid", proxy_conn->state);
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
static int _proxy_handshake_http(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
int len = 0;
|
||||
proxy_handshake_state ret = PROXY_HANDSHAKE_ERR;
|
||||
char buff[4096];
|
||||
struct http_head *http_head = NULL;
|
||||
|
||||
switch (proxy_conn->state) {
|
||||
case PROXY_CONN_INIT: {
|
||||
char connecthost[DNS_MAX_CNAME_LEN * 2];
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
getaddr_by_host(proxy_conn->host, (struct sockaddr *)&addr, &addr_len);
|
||||
|
||||
if (proxy_conn->server_info->info.use_domain) {
|
||||
snprintf(connecthost, sizeof(connecthost), "%s:%d", proxy_conn->host, proxy_conn->port);
|
||||
} else {
|
||||
struct sockaddr_in *addr_in;
|
||||
addr_in = (struct sockaddr_in *)&addr;
|
||||
unsigned char *paddr = (unsigned char *)&addr_in->sin_addr.s_addr;
|
||||
snprintf(connecthost, sizeof(connecthost), "%d.%d.%d.%d:%d", paddr[0], paddr[1], paddr[2], paddr[3],
|
||||
proxy_conn->port);
|
||||
}
|
||||
|
||||
int msglen = 0;
|
||||
|
||||
if (proxy_conn->server_info->info.username[0] == '\0') {
|
||||
msglen = snprintf(buff, sizeof(buff),
|
||||
"CONNECT %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Proxy-Connection: Keep-Alive\r\n\r\n",
|
||||
connecthost, connecthost);
|
||||
} else {
|
||||
char auth[256];
|
||||
char base64_auth[256 * 2];
|
||||
snprintf(auth, sizeof(auth), "%s:%s", proxy_conn->server_info->info.username,
|
||||
proxy_conn->server_info->info.password);
|
||||
SSL_base64_encode(auth, strlen(auth), base64_auth);
|
||||
|
||||
msglen = snprintf(buff, sizeof(buff),
|
||||
"CONNECT %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Proxy-Authorization: Basic %s\r\n"
|
||||
"Proxy-Connection: Keep-Alive\r\n\r\n",
|
||||
connecthost, connecthost, base64_auth);
|
||||
}
|
||||
|
||||
len = send(proxy_conn->fd, buff, msglen, MSG_NOSIGNAL);
|
||||
if (len != msglen) {
|
||||
tlog(TLOG_ERROR, "init https failed, len = %d, errno = %s", len, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
proxy_conn->state = PROXY_CONN_CONNECTING;
|
||||
ret = PROXY_HANDSHAKE_WANT_READ;
|
||||
goto out;
|
||||
} break;
|
||||
case PROXY_CONN_CONNECTING: {
|
||||
http_head = http_head_init(4096);
|
||||
if (http_head == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = recv(proxy_conn->fd, buff, sizeof(buff), 0);
|
||||
if (len <= 0) {
|
||||
if (len == 0) {
|
||||
tlog(TLOG_ERROR, "remote server closed.");
|
||||
} else {
|
||||
tlog(TLOG_ERROR, "recv failed, errno = %s", strerror(errno));
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = http_head_parse(http_head, buff, len);
|
||||
if (len < 0) {
|
||||
if (len == -1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "remote server not supported.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (http_head_get_httpcode(http_head) != 200) {
|
||||
tlog(TLOG_WARN, "http server query failed, server return http code : %d, %s",
|
||||
http_head_get_httpcode(http_head), http_head_get_httpcode_msg(http_head));
|
||||
goto out;
|
||||
}
|
||||
|
||||
proxy_conn->state = PROXY_CONN_CONNECTED;
|
||||
ret = PROXY_HANDSHAKE_CONNECTED;
|
||||
goto out;
|
||||
} break;
|
||||
default:
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (http_head) {
|
||||
http_head_destroy(http_head);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
proxy_handshake_state proxy_conn_handshake(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
if (proxy_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (proxy_conn->state == PROXY_CONN_CONNECTED) {
|
||||
return PROXY_HANDSHAKE_OK;
|
||||
}
|
||||
|
||||
switch (proxy_conn->type) {
|
||||
case PROXY_SOCKS5:
|
||||
return _proxy_handshake_socks5(proxy_conn);
|
||||
case PROXY_HTTP:
|
||||
return _proxy_handshake_http(proxy_conn);
|
||||
default:
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
return PROXY_HANDSHAKE_ERR;
|
||||
}
|
||||
|
||||
static int _proxy_is_tcp_connected(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
char buff[1];
|
||||
int ret = 0;
|
||||
ret = recv(proxy_conn->fd, buff, 1, MSG_PEEK | MSG_DONTWAIT);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_conn_sendto(struct proxy_conn *proxy_conn, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen)
|
||||
{
|
||||
char buffer[PROXY_BUFFER_SIZE];
|
||||
int buffer_len = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (proxy_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_proxy_is_tcp_connected(proxy_conn) == 0) {
|
||||
errno = ECONNRESET;
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer[0] = 0x00;
|
||||
buffer[1] = 0x00;
|
||||
buffer[2] = 0x00;
|
||||
buffer_len += 3;
|
||||
|
||||
switch (dest_addr->sa_family) {
|
||||
case AF_INET:
|
||||
buffer[3] = PROXY_SOCKS5_TYPE_IPV4;
|
||||
memcpy(buffer + 4, &((struct sockaddr_in *)dest_addr)->sin_addr.s_addr, 4);
|
||||
memcpy(buffer + 8, &((struct sockaddr_in *)dest_addr)->sin_port, 2);
|
||||
buffer_len += 7;
|
||||
break;
|
||||
case AF_INET6:
|
||||
buffer[3] = PROXY_SOCKS5_TYPE_IPV6;
|
||||
memcpy(buffer + 4, &((struct sockaddr_in6 *)dest_addr)->sin6_addr.s6_addr, 16);
|
||||
memcpy(buffer + 20, &((struct sockaddr_in6 *)dest_addr)->sin6_port, 2);
|
||||
buffer_len += 19;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buffer + buffer_len, buf, len);
|
||||
buffer_len += len;
|
||||
|
||||
ret = sendto(proxy_conn->udp_fd, buffer, buffer_len, MSG_NOSIGNAL, (struct sockaddr *)&proxy_conn->udp_dest_addr,
|
||||
proxy_conn->udp_dest_addrlen);
|
||||
if (ret != buffer_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int proxy_conn_recvfrom(struct proxy_conn *proxy_conn, void *buf, size_t len, int flags, struct sockaddr *src_addr,
|
||||
socklen_t *addrlen)
|
||||
{
|
||||
char buffer[PROXY_BUFFER_SIZE];
|
||||
int buffer_len = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (proxy_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = recvfrom(proxy_conn->udp_fd, buffer, sizeof(buffer), MSG_NOSIGNAL, NULL, 0);
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer[0] != 0x00 || buffer[1] != 0x00 || buffer[2] != 0x00) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (buffer[3]) {
|
||||
case PROXY_SOCKS5_TYPE_IPV4:
|
||||
if (ret < 10) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (src_addr) {
|
||||
memset(src_addr, 0, sizeof(struct sockaddr_in));
|
||||
((struct sockaddr_in *)src_addr)->sin_family = AF_INET;
|
||||
memcpy(&((struct sockaddr_in *)src_addr)->sin_addr.s_addr, buffer + 4, 4);
|
||||
memcpy(&((struct sockaddr_in *)src_addr)->sin_port, buffer + 8, 2);
|
||||
}
|
||||
|
||||
if (addrlen) {
|
||||
*addrlen = sizeof(struct sockaddr_in);
|
||||
}
|
||||
|
||||
buffer_len = 10;
|
||||
break;
|
||||
case PROXY_SOCKS5_TYPE_IPV6:
|
||||
if (ret < 22) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (src_addr) {
|
||||
memset(src_addr, 0, sizeof(struct sockaddr_in6));
|
||||
((struct sockaddr_in6 *)src_addr)->sin6_family = AF_INET6;
|
||||
memcpy(&((struct sockaddr_in6 *)src_addr)->sin6_addr.s6_addr, buffer + 4, 16);
|
||||
memcpy(&((struct sockaddr_in6 *)src_addr)->sin6_port, buffer + 20, 2);
|
||||
}
|
||||
|
||||
if (addrlen) {
|
||||
*addrlen = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
|
||||
buffer_len = 22;
|
||||
break;
|
||||
default:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret - buffer_len > (int)len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buf, buffer + buffer_len, ret - buffer_len);
|
||||
return ret - buffer_len;
|
||||
}
|
||||
|
||||
int proxy_conn_get_fd(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
if (proxy_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return proxy_conn->fd;
|
||||
}
|
||||
|
||||
int proxy_conn_get_udpfd(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
if (proxy_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return proxy_conn->udp_fd;
|
||||
}
|
||||
|
||||
int proxy_conn_is_udp(struct proxy_conn *proxy_conn)
|
||||
{
|
||||
if (proxy_conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return proxy_conn->is_udp;
|
||||
}
|
||||
|
||||
int proxy_init()
|
||||
{
|
||||
memset(&proxy, 0, sizeof(proxy));
|
||||
hash_init(proxy.proxy_server);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_exit()
|
||||
{
|
||||
_proxy_remove_all();
|
||||
return 0;
|
||||
}
|
||||
88
src/proxy.h
Normal file
88
src/proxy.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SMART_DNS_PROXY_H
|
||||
#define SMART_DNS_PROXY_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define PROXY_MAX_IPLEN 256
|
||||
#define PROXY_MAX_NAMELEN 128
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /*__cplusplus */
|
||||
|
||||
typedef enum {
|
||||
PROXY_SOCKS5,
|
||||
PROXY_HTTP,
|
||||
PROXY_TYPE_END,
|
||||
} proxy_type_t;
|
||||
|
||||
typedef enum {
|
||||
PROXY_HANDSHAKE_ERR = -1,
|
||||
PROXY_HANDSHAKE_OK = 0,
|
||||
PROXY_HANDSHAKE_CONNECTED = 1,
|
||||
PROXY_HANDSHAKE_WANT_READ = 2,
|
||||
PROXY_HANDSHAKE_WANT_WRITE = 3,
|
||||
} proxy_handshake_state;
|
||||
|
||||
struct proxy_info {
|
||||
proxy_type_t type;
|
||||
char server[PROXY_MAX_IPLEN];
|
||||
unsigned short port;
|
||||
int use_domain;
|
||||
char username[PROXY_MAX_NAMELEN];
|
||||
char password[PROXY_MAX_NAMELEN];
|
||||
};
|
||||
|
||||
struct proxy_conn;
|
||||
|
||||
int proxy_init(void);
|
||||
|
||||
int proxy_exit(void);
|
||||
|
||||
int proxy_add(const char *proxy_name, struct proxy_info *info);
|
||||
|
||||
int proxy_remove(const char *proxy_name);
|
||||
|
||||
struct proxy_conn *proxy_conn_new(const char *proxy_name, const char *host, int port, int is_udp);
|
||||
|
||||
int proxy_conn_get_fd(struct proxy_conn *proxy_conn);
|
||||
|
||||
int proxy_conn_get_udpfd(struct proxy_conn *proxy_conn);
|
||||
|
||||
int proxy_conn_is_udp(struct proxy_conn *proxy_conn);
|
||||
|
||||
void proxy_conn_free(struct proxy_conn *proxy_conn);
|
||||
|
||||
int proxy_conn_connect(struct proxy_conn *proxy_conn);
|
||||
|
||||
int proxy_conn_sendto(struct proxy_conn *proxy_conn, const void *buf, size_t len, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
|
||||
int proxy_conn_recvfrom(struct proxy_conn *proxy_conn, void *buf, size_t len, int flags, struct sockaddr *src_addr,
|
||||
socklen_t *addrlen);
|
||||
|
||||
proxy_handshake_state proxy_conn_handshake(struct proxy_conn *proxy_conn);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus */
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -270,6 +270,7 @@ static int _smartdns_add_servers(void)
|
||||
flags.server_flag = dns_conf_servers[i].server_flag;
|
||||
flags.result_flag = dns_conf_servers[i].result_flag;
|
||||
flags.set_mark = dns_conf_servers[i].set_mark;
|
||||
safe_strncpy(flags.proxyname, dns_conf_servers[i].proxyname, sizeof(flags.proxyname));
|
||||
ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type,
|
||||
&flags);
|
||||
if (ret != 0) {
|
||||
@@ -302,6 +303,33 @@ static int _smartdns_add_servers(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _proxy_add_servers(void)
|
||||
{
|
||||
unsigned long i = 0;
|
||||
struct hlist_node *tmp = NULL;
|
||||
struct dns_proxy_names *proxy = NULL;
|
||||
struct dns_proxy_servers *server = NULL;
|
||||
struct dns_proxy_servers *server_tmp = NULL;
|
||||
|
||||
hash_for_each_safe(dns_proxy_table.proxy, i, tmp, proxy, node)
|
||||
{
|
||||
list_for_each_entry_safe(server, server_tmp, &proxy->server_list, list)
|
||||
{
|
||||
struct proxy_info info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.type = server->type;
|
||||
info.port = server->port;
|
||||
safe_strncpy(info.server, server->server, PROXY_MAX_IPLEN);
|
||||
safe_strncpy(info.username, server->username, PROXY_MAX_NAMELEN);
|
||||
safe_strncpy(info.password, server->password, PROXY_MAX_NAMELEN);
|
||||
info.use_domain = server->use_domain;
|
||||
proxy_add(proxy->proxy_name, &info);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _smartdns_set_ecs_ip(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -386,6 +414,17 @@ static int _smartdns_init(void)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = proxy_init();
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "start proxy failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = _proxy_add_servers();
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "add proxy servers failed.");
|
||||
}
|
||||
|
||||
ret = dns_server_init();
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "start dns server failed.\n");
|
||||
@@ -397,6 +436,7 @@ static int _smartdns_init(void)
|
||||
tlog(TLOG_ERROR, "start dns client failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = _smartdns_add_servers();
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "add servers failed.");
|
||||
@@ -423,6 +463,7 @@ static void _smartdns_exit(void)
|
||||
{
|
||||
tlog(TLOG_INFO, "smartdns exit...");
|
||||
dns_client_exit();
|
||||
proxy_exit();
|
||||
fast_ping_exit();
|
||||
dns_server_exit();
|
||||
_smartdns_destroy_ssl();
|
||||
|
||||
22
src/util.c
22
src/util.c
@@ -1,6 +1,6 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -684,6 +684,24 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int SSL_base64_encode(const void *in, int in_len, char *out)
|
||||
{
|
||||
int outlen = 0;
|
||||
|
||||
if (in_len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
outlen = EVP_EncodeBlock((unsigned char *)out, in, in_len);
|
||||
if (outlen < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return outlen;
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int create_pid_file(const char *pid_file)
|
||||
{
|
||||
int fd = 0;
|
||||
@@ -1469,7 +1487,7 @@ int dns_packet_debug(const char *packet_file)
|
||||
char buff[DNS_PACKSIZE];
|
||||
|
||||
tlog_set_maxlog_count(0);
|
||||
tlog_setlogscreen(1);;
|
||||
tlog_setlogscreen(1);
|
||||
tlog_setlevel(TLOG_DEBUG);
|
||||
|
||||
info = _dns_read_packet_file(packet_file);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -89,6 +89,8 @@ unsigned char *SSL_SHA256(const unsigned char *d, size_t n, unsigned char *md);
|
||||
|
||||
int SSL_base64_decode(const char *in, unsigned char *out);
|
||||
|
||||
int SSL_base64_encode(const void *in, int in_len, char *out);
|
||||
|
||||
int create_pid_file(const char *pid_file);
|
||||
|
||||
/* Parse a TLS packet for the Server Name Indication extension in the client
|
||||
|
||||
Reference in New Issue
Block a user