Skip to content

Commit

Permalink
server: return formerr when recv malformed packet.
Browse files Browse the repository at this point in the history
  • Loading branch information
pymumu committed Jan 25, 2024
1 parent 9b13390 commit 40d859e
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 22 deletions.
2 changes: 2 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
从对比看出,SmartDNS 找到了访问 www.baidu.com 最快的 IP 地址,比阿里 DNS 速度快了 5 倍。

## 特性
1. **多虚拟DNS服务器**
支持多个虚拟DNS服务器,不同虚拟DNS服务器不同的端口,规则,客户端。

1. **多 DNS 上游服务器**
支持配置多个上游 DNS 服务器,并同时进行查询,即使其中有 DNS 服务器异常,也不会影响查询。
Expand Down
5 changes: 4 additions & 1 deletion ReadMe_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,17 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co

## Features

1. **Multiple Virtual DNS server**
Support multiple virtual DNS servers with different ports, rules, and clients.

1. **Multiple upstream DNS servers**
Support configuring multiple upstream DNS servers and query at the same time.the query will not be affected, Even if there is a DNS server exception.

1. **Support per-client query control**
Support controlling clients using different query rules based on MAC and IP addresses, enabling features such as parental control.

1. **Return the fastest IP address**
Supports finding the fastest access IP address from the IP address list of the domain name and returning it to the client to avoid DNS pollution and improve network access speed.
Support finding the fastest access IP address from the IP address list of the domain name and returning it to the client to avoid DNS pollution and improve network access speed.

1. **Support for multiple query protocols**
Support UDP, TCP, DOT(DNS over TLS), DOH(DNS over HTTPS) queries and service, and non-53 port queries, effectively avoiding DNS pollution and protect privacy, and support query DNS over socks5, http proxy.
Expand Down
12 changes: 9 additions & 3 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,22 @@ override CFLAGS += $(EXTRA_CFLAGS)

ifdef VER
override CFLAGS += -DSMARTDNS_VERION='"$(VER)"'
else
HAS_GIT := $(shell command -v git 2> /dev/null)
endif

HAS_GIT := $(shell command -v git 2> /dev/null)
ifndef NO_GIT_VER
ifdef HAS_GIT
IS_GIT_REPO := $(shell git rev-parse --is-inside-work-tree 2>/dev/null)
ifdef IS_GIT_REPO
override CFLAGS += -DSMARTDNS_VERION='"$(shell git describe --tags --always --dirty)"'
override COMMIT_VERION = $(shell git describe --tags --always --dirty)
endif
endif
endif

ifdef COMMIT_VERION
override CFLAGS += -DCOMMIT_VERION='"$(shell git describe --tags --always --dirty)"'
endif

CXXFLAGS=-O2 -g -Wall -std=c++11
override CXXFLAGS +=-Iinclude

Expand Down
30 changes: 30 additions & 0 deletions src/dns.c
Original file line number Diff line number Diff line change
Expand Up @@ -2777,6 +2777,36 @@ int dns_packet_init(struct dns_packet *packet, int size, struct dns_head *head)
return 0;
}

int dns_decode_head_only(struct dns_packet *packet, int maxsize, unsigned char *data, int size)
{
struct dns_head *head = &packet->head;
struct dns_context context;
int ret = 0;

memset(&context, 0, sizeof(context));
memset(packet, 0, sizeof(*packet));

context.data = data;
context.packet = packet;
context.ptr = data;
context.maxsize = size;
context.namedict = &packet->namedict;

ret = dns_packet_init(packet, maxsize, head);
if (ret != 0) {
return -1;
}

ret = _dns_decode_head(&context);
if (ret < 0) {
return -1;
}

packet->size = context.ptr - context.data + sizeof(*packet);

return 0;
}

int dns_decode(struct dns_packet *packet, int maxsize, unsigned char *data, int size)
{
struct dns_head *head = &packet->head;
Expand Down
1 change: 1 addition & 0 deletions src/dns.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct d
/*
* Packet operation
*/
int dns_decode_head_only(struct dns_packet *packet, int maxsize, unsigned char *data, int size);
int dns_decode(struct dns_packet *packet, int maxsize, unsigned char *data, int size);
int dns_encode(unsigned char *data, int size, struct dns_packet *packet);

Expand Down
28 changes: 20 additions & 8 deletions src/dns_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -2483,7 +2483,16 @@ static int _dns_client_process_udp_proxy(struct dns_server_info *server_info, st

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));
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return 0;
}

if (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH) {
tlog(TLOG_DEBUG, "recvfrom %s failed, %s\n", server_info->ip, strerror(errno));
goto errout;
}

tlog(TLOG_ERROR, "recvfrom %s failed, %s\n", server_info->ip, strerror(errno));
goto errout;
} else if (len == 0) {
pthread_mutex_lock(&client.server_list_lock);
Expand Down Expand Up @@ -2560,6 +2569,7 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
return 0;
}

server_info->prohibit = 1;
if (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH) {
tlog(TLOG_DEBUG, "recvfrom %s failed, %s\n", server_info->ip, strerror(errno));
goto errout;
Expand Down Expand Up @@ -2649,7 +2659,8 @@ static int _dns_client_socket_ssl_send(struct dns_server_info *server, const voi
errno = EAGAIN;
ret = -SSL_ERROR_WANT_WRITE;
break;
case SSL_ERROR_SSL:
case SSL_ERROR_SSL: {
char buff[256];
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 ||
Expand All @@ -2659,10 +2670,10 @@ static int _dns_client_socket_ssl_send(struct dns_server_info *server, const voi
return -1;
}

tlog(TLOG_ERROR, "SSL write fail error no: %s(%d)\n", ERR_reason_error_string(ssl_err), ssl_reason);
tlog(TLOG_ERROR, "server %s SSL write fail error: %s", server->ip, ERR_error_string(ssl_err, buff));
errno = EFAULT;
ret = -1;
break;
} break;
case SSL_ERROR_SYSCALL:
tlog(TLOG_DEBUG, "SSL syscall failed, %s", strerror(errno));
return ret;
Expand Down Expand Up @@ -2705,7 +2716,9 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
errno = EAGAIN;
ret = -SSL_ERROR_WANT_WRITE;
break;
case SSL_ERROR_SSL:
case SSL_ERROR_SSL: {
char buff[256];

ssl_err = ERR_get_error();
int ssl_reason = ERR_GET_REASON(ssl_err);
if (ssl_reason == SSL_R_UNINITIALIZED) {
Expand All @@ -2723,11 +2736,10 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
}
#endif

tlog(TLOG_WARN, "SSL read fail error no: %s(%lx), reason: %d\n", ERR_reason_error_string(ssl_err), ssl_err,
ssl_reason);
tlog(TLOG_ERROR, "server %s SSL read fail error: %s", server->ip, ERR_error_string(ssl_err, buff));
errno = EFAULT;
ret = -1;
break;
} break;
case SSL_ERROR_SYSCALL:
if (errno == 0) {
return 0;
Expand Down
61 changes: 58 additions & 3 deletions src/dns_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,10 @@ static int _dns_setup_dns_packet(struct dns_server_post_context *context)
return -1;
}

if (request->domain[0] == '\0') {
return 0;
}

/* add request domain */
ret = dns_add_domain(context->packet, request->domain, context->qtype, request->qclass);
if (ret != 0) {
Expand Down Expand Up @@ -6624,6 +6628,48 @@ static int _dns_server_parser_request(struct dns_request *request, struct dns_pa
return -1;
}

static int _dns_server_reply_format_error(struct dns_request *request, struct dns_server_conn_head *conn,
unsigned char *inpacket, int inpacket_len, struct sockaddr_storage *local,
socklen_t local_len, struct sockaddr_storage *from, socklen_t from_len)
{
unsigned char packet_buff[DNS_PACKSIZE];
struct dns_packet *packet = (struct dns_packet *)packet_buff;
int decode_len = 0;
int need_release = 0;
int ret = -1;

if (request == NULL) {
decode_len = dns_decode_head_only(packet, DNS_PACKSIZE, inpacket, inpacket_len);
if (decode_len < 0) {
ret = -1;
goto out;
}

request = _dns_server_new_request();
if (request == NULL) {
ret = -1;
goto out;
}

need_release = 1;
memcpy(&request->localaddr, local, local_len);
_dns_server_request_set_client(request, conn);
_dns_server_request_set_client_addr(request, from, from_len);
_dns_server_request_set_id(request, packet->head.id);
}

request->rcode = DNS_RC_FORMERR;
request->no_cache = 1;
request->send_tick = get_tick_count();
ret = 0;
out:
if (request && need_release) {
_dns_server_request_release(request);
}

return ret;
}

static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *inpacket, int inpacket_len,
struct sockaddr_storage *local, socklen_t local_len, struct sockaddr_storage *from,
socklen_t from_len)
Expand Down Expand Up @@ -6687,9 +6733,7 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
last_log_time = now;
tlog(TLOG_WARN, "maximum number of dns queries reached, max: %d", dns_conf_max_query_limit);
}
request->send_tick = get_tick_count();
request->rcode = DNS_RC_REFUSED;
request->no_cache = 1;
ret = 0;
goto errout;
}
Expand All @@ -6708,7 +6752,16 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
_dns_server_request_release_complete(request, 0);
return ret;
errout:
if (ret == RECV_ERROR_INVALID_PACKET) {
if (_dns_server_reply_format_error(request, conn, inpacket, inpacket_len, local, local_len, from, from_len) ==
0) {
ret = 0;
}
}

if (request) {
request->send_tick = get_tick_count();
request->no_cache = 1;
_dns_server_forward_request(inpacket, inpacket_len);
_dns_server_request_release(request);
}
Expand Down Expand Up @@ -7405,7 +7458,8 @@ static int _dns_server_tcp_process_one_request(struct dns_server_conn_tcp_client
free(http_decode_data);
}

if (ret == RECV_ERROR_FAIL && tcpclient->head.type == DNS_CONN_TYPE_HTTPS_CLIENT) {
if ((ret == RECV_ERROR_FAIL || ret == RECV_ERROR_INVALID_PACKET) &&
tcpclient->head.type == DNS_CONN_TYPE_HTTPS_CLIENT) {
_dns_server_reply_http_error(tcpclient, 400, "Bad Request", "Bad Request");
}

Expand Down Expand Up @@ -8797,6 +8851,7 @@ int dns_server_init(void)

if (_dns_server_local_addr_cache_init() != 0) {
tlog(TLOG_WARN, "init local addr cache failed, disable local ptr.");
dns_conf_local_ptr_enable = 0;
}

if (_dns_server_neighbor_cache_init() != 0) {
Expand Down
26 changes: 19 additions & 7 deletions src/smartdns.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,28 @@ static void _help(void)
printf("%s", help);
}

static void _show_version(void)
static void _smartdns_get_version(char *str_ver, int str_ver_len)
{
char str_ver[256] = {0};
char commit_ver[TMP_BUFF_LEN_32] = {0};
#ifdef COMMIT_VERION
snprintf(commit_ver, sizeof(commit_ver), " (%s)", COMMIT_VERION);
#endif

#ifdef SMARTDNS_VERION
const char *ver = SMARTDNS_VERION;
snprintf(str_ver, sizeof(str_ver), "%s", ver);
snprintf(str_ver, str_ver_len, "%s%s", ver, commit_ver);
#else
struct tm tm;
get_compiled_time(&tm);
snprintf(str_ver, sizeof(str_ver), "1.%.4d%.2d%.2d-%.2d%.2d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min);
snprintf(str_ver, str_ver_len, "1.%.4d%.2d%.2d-%.2d%.2d%s", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, commit_ver);
#endif
}

static void _show_version(void)
{
char str_ver[256] = {0};
_smartdns_get_version(str_ver, sizeof(str_ver));
printf("smartdns %s\n", str_ver);
}

Expand Down Expand Up @@ -618,14 +628,16 @@ static int _smartdns_init_load_from_resolv(void)
static int _smartdns_init(void)
{
int ret = 0;
char str_ver[256] = {0};

if (_smartdns_init_log() != 0) {
tlog(TLOG_ERROR, "init log failed.");
goto errout;
}

tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <[email protected]>, build: %s %s)", __DATE__,
__TIME__);
_smartdns_get_version(str_ver, sizeof(str_ver));

tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <[email protected]>, build: %s)", str_ver);

if (dns_timer_init() != 0) {
tlog(TLOG_ERROR, "init timer failed.");
Expand Down

0 comments on commit 40d859e

Please sign in to comment.