Compare commits

..

27 Commits

Author SHA1 Message Date
MoetaYuko
1ba6ee7cb9 openwrt: add missing EOF to custom.conf 2023-08-09 23:31:15 +08:00
Nick Peng
601ebd590e ssl: output error message when handshake failed. 2023-08-06 21:15:04 +08:00
Nick Peng
b133ce408a dns_conf: fix memory corruption issue when ip number greater than 8. 2023-07-28 22:42:36 +08:00
Nick Peng
8d3a62c568 dns_server: fix bogus-nxdomain issue. 2023-07-26 22:40:26 +08:00
Nick Peng
93a8b87c17 dns_server: fix memory corrupt bug. 2023-07-17 21:47:14 +08:00
Nick Peng
ffc331af21 dns-client: fix bootstrap retry failure issue when os startup. 2023-07-15 21:04:27 +08:00
Nick Peng
89e958abfa dns_client: avoid false re-creation of udp sockets causing retries. 2023-07-14 20:44:10 +08:00
Nick Peng
2576fdb02f dns_client: fix bootstrap dns retry issue. 2023-07-12 22:37:22 +08:00
Nick Peng
7ff6ae3ea0 dns_server: fix edns subnet not working issue. 2023-07-12 19:28:37 +08:00
Nick Peng
c2b072b523 conf: add ddns-domain options 2023-07-12 19:28:32 +08:00
Nick Peng
1df9d624b4 conf: add host-ip option for server. 2023-07-12 19:13:11 +08:00
Nick Peng
6b021946aa conf: support prefix wildcard match. 2023-07-05 00:08:29 +08:00
Nick Peng
087c9f5df2 conf: fix address issue when configuring multiple IPs 2023-07-01 09:20:42 +08:00
Nick Peng
e66928f27f ecs: Optimize ecs-subnet configuration method 2023-06-28 14:23:27 +08:00
Nick Peng
8a9a11d6d9 log: enable output log to console when run as daemon. 2023-06-16 21:57:39 +08:00
Nick Peng
a6e5ceb675 conf: trim prefix space for multiline option 2023-06-15 21:18:08 +08:00
Nick Peng
08567c458b address: support multiple ip addresses 2023-06-14 22:41:53 +08:00
Nick Peng
234c721011 test: fix test case failure issue 2023-06-14 22:40:12 +08:00
Chongyun Lee
45346705d8 tlog: fix declaration of tlog_set_permission 2023-06-11 07:02:37 +08:00
Nick Peng
9b7b2ad12d openwrt: fix adblock not working issue 2023-06-07 23:54:26 +08:00
Nick Peng
f072ff3412 dns_server: optimize result callback and update tlog. 2023-06-07 21:15:59 +08:00
Nick Peng
ad43c796cf force-qtype-SOA: support qtype range. 2023-06-05 22:55:47 +08:00
Nick Peng
f5c8d3ce57 dns_server: improve code readability 2023-06-02 22:52:46 +08:00
Nick Peng
f621b424e2 lint: add clang-tidy linter 2023-05-30 23:26:05 +08:00
Nick Peng
d59c148a28 smartdns: follow sysv daemon initialize steps 2023-05-30 23:25:25 +08:00
Nick Peng
8ea34ab176 dns_conf: A little bit of performance optimization 2023-05-27 22:51:00 +08:00
Nick Peng
0340d272c3 dns_server: fix max ttl reply issue. 2023-05-09 23:22:08 +08:00
31 changed files with 1644 additions and 387 deletions

43
.clang-tidy Normal file
View File

@@ -0,0 +1,43 @@
Checks: >
-*,
modernize-*,
bugprone-*,
concurrency-*,
misc-*,
readability-*,
performance-*,
portability-*,
google-*,
linuxkernel-*,
-bugprone-narrowing-conversions,
-bugprone-branch-clone,
-bugprone-reserved-identifier,
-bugprone-easily-swappable-parameters,
-bugprone-sizeof-expression,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-suspicious-memory-comparison,
-bugprone-not-null-terminated-result,
-bugprone-signal-handler,
-concurrency-mt-unsafe,
-misc-unused-parameters,
-misc-misplaced-widening-cast,
-misc-no-recursion,
-readability-magic-numbers,
-readability-use-anyofallof,
-readability-identifier-length,
-readability-function-cognitive-complexity,
-readability-named-parameter,
-readability-isolate-declaration,
-readability-else-after-return,
-readability-redundant-control-flow,
-readability-suspicious-call-argument,
-google-readability-casting,
-google-readability-todo,
-performance-no-int-to-ptr,
# clang-analyzer-*,
# clang-analyzer-deadcode.DeadStores,
# clang-analyzer-optin.performance.Padding,
# -clang-analyzer-security.insecureAPI.*
# Turn all the warnings from the checks above into errors.
FormatStyle: file

View File

@@ -194,6 +194,7 @@ log-level info
# -bootstrap-dns: set as bootstrap dns server.
# -set-mark: set mark on packets.
# -subnet [ip/subnet]: set edns client subnet.
# -host-ip [ip]: set dns server host ip.
# server 8.8.8.8 -blacklist-ip -check-edns -group g1 -group g2
# server tls://dns.google:853
# server https://dns.google/dns-query
@@ -247,8 +248,9 @@ log-level info
# expand-ptr-from-address yes
# specific address to domain
# address /domain/[ip|-|-4|-6|#|#4|#6]
# address /domain/[ip1,ip2|-|-4|-6|#|#4|#6]
# address /www.example.com/1.2.3.4, return ip 1.2.3.4 to client
# address /www.example.com/1.2.3.4,5.6.7.8, return multiple ip addresses
# address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all
# address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all
@@ -289,6 +291,9 @@ log-level info
# nftset /www.example.com/-, ignore this domain
# nftset /www.example.com/#6:-, ignore ipv6
# set ddns domain
# ddns-domain domain
# set domain rules
# domain-rules /domain/ [-speed-check-mode [...]]
# rules:

View File

@@ -308,7 +308,7 @@ load_domain_rules()
config_get block_domain_set_file "$section" "block_domain_set_file"
[ ! -z "$block_domain_set_file" ] && {
conf_append "domain-set" "-name ${domain_set_name}-block-file -file '$block_domain_set_file'"
conf_append "domain-rules" "/domain-set:${domain_set_name}-block-file/ -group block"
conf_append "domain-rules" "/domain-set:${domain_set_name}-block-file/ --address #"
}
conf_append "domain-set" "-name ${domain_set_name}-block-list -file /etc/smartdns/domain-block.list"

View File

@@ -15,8 +15,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
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 proxy.o $(OBJS_LIB)
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o
OBJS_MAIN=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 lib/conf.o lib/nftset.o
OBJS=$(OBJS_MAIN) $(OBJS_LIB)
# cflags
ifndef CFLAGS
@@ -51,5 +52,8 @@ all: $(BIN)
$(BIN) : $(OBJS)
$(CC) $(OBJS) -o $@ $(LDFLAGS)
clang-tidy:
clang-tidy -p=. $(OBJS_MAIN:.o=.c) -- $(CFLAGS)
clean:
$(RM) $(OBJS) $(BIN)

View File

@@ -875,6 +875,27 @@ int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *
return _dns_get_RAW(rrs, domain, maxsize, ttl, cname, &len);
}
int dns_add_TXT(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *text)
{
int rr_len = strnlen(text, DNS_MAX_CNAME_LEN);
char data[DNS_MAX_CNAME_LEN];
if (rr_len > DNS_MAX_CNAME_LEN - 2) {
return -1;
}
data[0] = rr_len;
rr_len++;
memcpy(data + 1, text, rr_len);
data[rr_len] = 0;
return _dns_add_RAW(packet, type, DNS_T_TXT, domain, ttl, data, rr_len);
}
int dns_get_TXT(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *text, int txt_size)
{
return -1;
}
int dns_add_NS(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname)
{
int rr_len = strnlen(cname, DNS_MAX_CNAME_LEN) + 1;

View File

@@ -262,6 +262,9 @@ int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned
int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname);
int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
int dns_add_TXT(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *text);
int dns_get_TXT(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *text, int txt_size);
int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl,
unsigned char addr[DNS_RR_AAAA_LEN]);
int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_AAAA_LEN]);
@@ -302,7 +305,7 @@ int dns_add_HTTPS_end(struct dns_rr_nested *svcparam);
int dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, struct dns_https_param **https_param, char *domain, int maxsize,
int *ttl, int *priority, char *target, int target_size);
struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *parm);
struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *param);
/*
* Packet operation

View File

@@ -63,7 +63,7 @@
#define DNS_TCP_CONNECT_TIMEOUT (5)
#define DNS_QUERY_TIMEOUT (500)
#define DNS_QUERY_RETRY (4)
#define DNS_PENDING_SERVER_RETRY 40
#define DNS_PENDING_SERVER_RETRY 60
#define SOCKET_PRIORITY (6)
#define SOCKET_IP_TOS (IPTOS_LOWDELAY | IPTOS_RELIABILITY)
@@ -161,7 +161,8 @@ struct dns_server_pending {
unsigned int has_v6;
unsigned int query_v4;
unsigned int query_v6;
unsigned int has_soa;
unsigned int has_soa_v4;
unsigned int has_soa_v6;
/* server type */
dns_server_type_t type;
@@ -442,8 +443,8 @@ static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int ty
ret = getaddrinfo(host, port, &hints, &result);
if (ret != 0) {
tlog(TLOG_ERROR, "get addr info failed. %s\n", gai_strerror(ret));
tlog(TLOG_ERROR, "host = %s, port = %s, type = %d, protocol = %d", host, port, type, protocol);
tlog(TLOG_WARN, "get addr info failed. %s\n", gai_strerror(ret));
tlog(TLOG_WARN, "host = %s, port = %s, type = %d, protocol = %d", host, port, type, protocol);
goto errout;
}
@@ -1402,6 +1403,8 @@ static int _dns_client_add_server_pending(char *server_ip, char *server_host, in
struct client_dns_server_flags *flags, int is_pending)
{
int ret = 0;
struct addrinfo *gai = NULL;
char server_ip_tmp[DNS_HOSTNAME_LEN] = {0};
if (server_type >= DNS_SERVER_TYPE_END) {
tlog(TLOG_ERROR, "server type is invalid.");
@@ -1414,6 +1417,22 @@ static int _dns_client_add_server_pending(char *server_ip, char *server_host, in
tlog(TLOG_INFO, "add pending server %s", server_ip);
return 0;
}
} else if (check_is_ipaddr(server_ip) && is_pending == 0) {
gai = _dns_client_getaddr(server_ip, 0, SOCK_STREAM, 0);
if (gai == NULL) {
return -1;
}
if (get_host_by_addr(server_ip_tmp, sizeof(server_ip_tmp), gai->ai_addr) != NULL) {
tlog(TLOG_INFO, "resolve %s to %s.", server_ip, server_ip_tmp);
server_ip = server_ip_tmp;
} else {
tlog(TLOG_INFO, "resolve %s failed.", server_ip);
freeaddrinfo(gai);
return -1;
}
freeaddrinfo(gai);
}
/* add server */
@@ -1783,13 +1802,8 @@ static int _dns_client_create_socket_udp_proxy(struct dns_server_info *server_in
ret = proxy_conn_connect(proxy);
if (ret != 0) {
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == EPERM || errno == EACCES) {
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));
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
goto errout;
}
}
@@ -1843,14 +1857,8 @@ static int _dns_client_create_socket_udp(struct dns_server_info *server_info)
server_info->status = DNS_SERVER_STATUS_CONNECTIONLESS;
if (connect(fd, &server_info->addr, server_info->ai_addrlen) != 0) {
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED || errno == EPERM ||
errno == EACCES) {
tlog(TLOG_INFO, "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));
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
goto errout;
}
}
@@ -1950,13 +1958,8 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
}
if (ret != 0) {
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED) {
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));
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
goto errout;
}
}
@@ -2064,13 +2067,8 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
}
if (ret != 0) {
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED) {
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));
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
goto errout;
}
}
@@ -2239,13 +2237,14 @@ static int _dns_client_process_udp_proxy(struct dns_server_info *server_info, st
}
int latency = get_tick_count() - server_info->send_tick;
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d, latency: %d",
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len, latency);
if (latency < server_info->drop_packet_latency_ms) {
tlog(TLOG_DEBUG, "drop packet from %s, latency: %d", from_host, latency);
return 0;
}
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d",
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len);
/* update recv time */
time(&server_info->last_recv);
@@ -2322,14 +2321,15 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
}
}
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d, ttl: %d",
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len, ttl);
int latency = get_tick_count() - server_info->send_tick;
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d, ttl: %d, latency: %d",
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len, ttl, latency);
/* update recv time */
time(&server_info->last_recv);
int latency = get_tick_count() - server_info->send_tick;
if (latency < server_info->drop_packet_latency_ms) {
tlog(TLOG_DEBUG, "drop packet from %s, latency: %d", from_host, latency);
return 0;
}
@@ -2818,7 +2818,7 @@ static int _dns_client_verify_common_name(struct dns_server_info *server_info, X
tlog(TLOG_DEBUG, "peer SAN: %s", dns->data);
if (_dns_client_tls_matchName(tls_host_verify, (char *)dns->data, dns->length) == 0) {
tlog(TLOG_INFO, "peer SAN match: %s", dns->data);
tlog(TLOG_DEBUG, "peer SAN match: %s", dns->data);
return 0;
}
} break;
@@ -2969,9 +2969,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
if (server_info->status == DNS_SERVER_STATUS_CONNECTING) {
/* do SSL hand shake */
ret = _ssl_do_handshake(server_info);
if (ret == 0) {
goto errout;
} else if (ret < 0) {
if (ret <= 0) {
memset(&fd_event, 0, sizeof(fd_event));
ssl_ret = _ssl_get_error(server_info, ret);
if (ssl_ret == SSL_ERROR_WANT_READ) {
@@ -3370,21 +3368,22 @@ static int _dns_client_setup_server_packet(struct dns_server_info *server_info,
struct dns_packet *packet = (struct dns_packet *)packet_buff;
struct dns_head head;
int encode_len = 0;
int repack = 0;
int hitchhiking = 0;
*packet_data = default_packet;
*packet_data_len = default_packet_len;
if (query->qtype != DNS_T_AAAA && query->qtype != DNS_T_A) {
/* no need to encode packet */
return 0;
if (server_info->ecs_ipv4.enable == true || server_info->ecs_ipv6.enable == true) {
repack = 1;
}
if (server_info->ecs_ipv4.enable == false && query->qtype == DNS_T_A) {
/* no need to encode packet */
return 0;
if ((server_info->flags.server_flag & SERVER_FLAG_HITCHHIKING) != 0) {
hitchhiking = 1;
repack = 1;
}
if (server_info->ecs_ipv6.enable == false && query->qtype == DNS_T_AAAA) {
if (repack == 0) {
/* no need to encode packet */
return 0;
}
@@ -3404,6 +3403,11 @@ static int _dns_client_setup_server_packet(struct dns_server_info *server_info,
return -1;
}
if (hitchhiking != 0 && dns_add_domain(packet, "-", query->qtype, DNS_C_IN) != 0) {
tlog(TLOG_ERROR, "add domain to packet failed.");
return -1;
}
/* add question */
if (dns_add_domain(packet, query->domain, query->qtype, DNS_C_IN) != 0) {
tlog(TLOG_ERROR, "add domain to packet failed.");
@@ -3412,10 +3416,16 @@ static int _dns_client_setup_server_packet(struct dns_server_info *server_info,
dns_set_OPT_payload_size(packet, DNS_IN_PACKSIZE);
/* dns_add_OPT_TCP_KEEPALIVE(packet, 600); */
if (query->qtype == DNS_T_A && server_info->ecs_ipv4.enable) {
if ((query->qtype == DNS_T_A && server_info->ecs_ipv4.enable)) {
dns_add_OPT_ECS(packet, &server_info->ecs_ipv4.ecs);
} else if (query->qtype == DNS_T_AAAA && server_info->ecs_ipv6.enable) {
} else if ((query->qtype == DNS_T_AAAA && server_info->ecs_ipv6.enable)) {
dns_add_OPT_ECS(packet, &server_info->ecs_ipv6.ecs);
} else {
if (server_info->ecs_ipv6.enable) {
dns_add_OPT_ECS(packet, &server_info->ecs_ipv6.ecs);
} else if (server_info->ecs_ipv4.enable) {
dns_add_OPT_ECS(packet, &server_info->ecs_ipv4.ecs);
}
}
/* encode packet */
@@ -3496,6 +3506,8 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
atomic_inc(&query->dns_request_sent);
send_count++;
errno = 0;
server_info->send_tick = get_tick_count();
switch (server_info->type) {
case DNS_SERVER_UDP:
/* udp query */
@@ -3548,7 +3560,6 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
continue;
}
time(&server_info->last_send);
server_info->send_tick = get_tick_count();
}
pthread_mutex_unlock(&client.server_list_lock);
@@ -3651,20 +3662,20 @@ static int _dns_client_query_setup_default_ecs(struct dns_query_struct *query)
if (client.ecs_ipv4.enable) {
add_ipv4_ecs = 1;
} else if (client.ecs_ipv6.enable) {
add_ipv4_ecs = 1;
add_ipv6_ecs = 1;
}
}
if (add_ipv4_ecs) {
memcpy(&query->ecs, &client.ecs_ipv4, sizeof(query->ecs));
return 0;
}
if (add_ipv6_ecs) {
memcpy(&query->ecs, &client.ecs_ipv6, sizeof(query->ecs));
return 0;
}
if (add_ipv4_ecs) {
memcpy(&query->ecs, &client.ecs_ipv4, sizeof(query->ecs));
return 0;
}
return 0;
}
@@ -3889,31 +3900,40 @@ static void _dns_client_check_servers(void)
pthread_mutex_unlock(&client.server_list_lock);
}
static int _dns_client_pending_server_resolve(const char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip,
unsigned int ping_time, void *user_ptr)
static int _dns_client_pending_server_resolve(const struct dns_result *result, void *user_ptr)
{
struct dns_server_pending *pending = user_ptr;
int ret = 0;
int has_soa = 0;
if (rtcode == DNS_RC_NXDOMAIN) {
pending->has_soa = 1;
if (result->rtcode == DNS_RC_NXDOMAIN || result->has_soa == 1 || result->rtcode == DNS_RC_REFUSED ||
(result->rtcode == DNS_RC_NOERROR && result->ip_num == 0)) {
has_soa = 1;
}
if (addr_type == DNS_T_A) {
if (result->addr_type == DNS_T_A) {
pending->ping_time_v4 = -1;
if (rtcode == DNS_RC_NOERROR) {
if (result->rtcode == DNS_RC_NOERROR && result->ip_num > 0) {
pending->has_v4 = 1;
pending->ping_time_v4 = ping_time;
pending->has_soa = 0;
safe_strncpy(pending->ipv4, ip, DNS_HOSTNAME_LEN);
pending->ping_time_v4 = result->ping_time;
pending->has_soa_v4 = 0;
safe_strncpy(pending->ipv4, result->ip, DNS_HOSTNAME_LEN);
} else if (has_soa) {
pending->has_v4 = 0;
pending->ping_time_v4 = -1;
pending->has_soa_v4 = 1;
}
} else if (addr_type == DNS_T_AAAA) {
} else if (result->addr_type == DNS_T_AAAA) {
pending->ping_time_v6 = -1;
if (rtcode == DNS_RC_NOERROR) {
if (result->rtcode == DNS_RC_NOERROR && result->ip_num > 0) {
pending->has_v6 = 1;
pending->ping_time_v6 = ping_time;
pending->has_soa = 0;
safe_strncpy(pending->ipv6, ip, DNS_HOSTNAME_LEN);
pending->ping_time_v6 = result->ping_time;
pending->has_soa_v6 = 0;
safe_strncpy(pending->ipv6, result->ip, DNS_HOSTNAME_LEN);
} else if (has_soa) {
pending->has_v6 = 0;
pending->ping_time_v6 = -1;
pending->has_soa_v6 = 1;
}
} else {
ret = -1;
@@ -4007,6 +4027,25 @@ static void _dns_client_add_pending_servers(void)
int add_success = 0;
char *dnsserver_ip = NULL;
/* if has no bootstrap DNS, just call getaddrinfo to get address */
if (dns_client_has_bootstrap_dns == 0) {
list_del_init(&pending->retry_list);
_dns_client_server_pending_release(pending);
pending->retry_cnt++;
if (_dns_client_add_pendings(pending, pending->host) != 0) {
pthread_mutex_unlock(&pending_server_mutex);
tlog(TLOG_INFO, "add pending DNS server %s from resolv.conf failed, retry %d...", pending->host,
pending->retry_cnt - 1);
if (pending->retry_cnt - 1 > DNS_PENDING_SERVER_RETRY) {
tlog(TLOG_WARN, "add pending DNS server %s from resolv.conf failed, exit...", pending->host);
exit(1);
}
continue;
}
_dns_client_server_pending_release(pending);
continue;
}
if (pending->query_v4 == 0) {
pending->query_v4 = 1;
_dns_client_server_pending_get(pending);
@@ -4021,7 +4060,7 @@ static void _dns_client_add_pending_servers(void)
_dns_client_server_pending_get(pending);
if (dns_server_query(pending->host, DNS_T_AAAA, 0, _dns_client_pending_server_resolve, pending) != 0) {
_dns_client_server_pending_release(pending);
pending->query_v4 = 0;
pending->query_v6 = 0;
}
}
@@ -4052,7 +4091,7 @@ static void _dns_client_add_pending_servers(void)
continue;
}
if (pending->has_soa && dnsserver_ip == NULL) {
if (dnsserver_ip == NULL && pending->has_soa_v4 && pending->has_soa_v6) {
tlog(TLOG_WARN, "add pending DNS server %s failed, no such host.", pending->host);
_dns_client_server_pending_remove(pending);
continue;
@@ -4068,22 +4107,6 @@ static void _dns_client_add_pending_servers(void)
pending->query_v4 = 0;
pending->query_v6 = 0;
}
/* if has no bootstrap DNS, just call getaddrinfo to get address */
if (dns_client_has_bootstrap_dns == 0) {
if (_dns_client_add_pendings(pending, pending->host) != 0) {
pthread_mutex_unlock(&pending_server_mutex);
tlog(TLOG_INFO, "add pending DNS server %s from resolv.conf failed, retry %d...", pending->host,
pending->retry_cnt - 1);
if (pending->retry_cnt - 1 > DNS_PENDING_SERVER_RETRY) {
tlog(TLOG_WARN, "add pending DNS server %s from resolv.conf failed, exit...", pending->host);
exit(1);
}
continue;
}
_dns_client_server_pending_release(pending);
}
}
}
@@ -4117,14 +4140,19 @@ static void _dns_client_period_run(unsigned int msec)
{
/* free timed out query, and notify caller */
list_del_init(&query->period_list);
/* check udp nat after retrying. */
if (atomic_read(&query->retry_count) == 1) {
_dns_client_check_udp_nat(query);
}
if (atomic_dec_and_test(&query->retry_count) || (query->has_result != 0)) {
_dns_client_query_remove(query);
if (query->has_result == 0) {
tlog(TLOG_INFO, "retry query %s, type: %d, id: %d failed", query->domain, query->qtype, query->sid);
tlog(TLOG_DEBUG, "retry query %s, type: %d, id: %d failed", query->domain, query->qtype, query->sid);
}
} else {
tlog(TLOG_INFO, "retry query %s, type: %d, id: %d", query->domain, query->qtype, query->sid);
tlog(TLOG_DEBUG, "retry query %s, type: %d, id: %d", query->domain, query->qtype, query->sid);
_dns_client_send_query(query);
}
_dns_client_query_release(query);

View File

@@ -30,7 +30,7 @@
#include <syslog.h>
#include <unistd.h>
#define DNS_MAX_REPLY_IP_NUM 8
#define TMP_BUFF_LEN 1024
/* ipset */
struct dns_ipset_table {
@@ -43,7 +43,7 @@ struct dns_nftset_table {
};
static struct dns_nftset_table dns_nftset_table;
struct dns_qtype_soa_table dns_qtype_soa_table;
uint8_t *dns_qtype_soa_table;
struct dns_domain_set_name_table dns_domain_set_name_table;
@@ -161,6 +161,8 @@ char dns_conf_user[DNS_CONF_USERNAME_LEN];
int dns_save_fail_packet;
char dns_save_fail_packet_dir[DNS_MAX_PATH];
char dns_resolv_file[DNS_MAX_PATH];
int dns_no_pidfile;
int dns_no_daemon;
/* ECS */
struct dns_edns_client_subnet dns_conf_ipv4_ecs;
@@ -172,8 +174,10 @@ static int _conf_domain_rule_nameserver(char *domain, const char *group_name);
static int _conf_ptr_add(const char *hostname, const char *ip, int is_dynamic);
static int _conf_client_subnet(char *subnet, struct dns_edns_client_subnet *ipv4_ecs,
struct dns_edns_client_subnet *ipv6_ecs);
static int _conf_domain_rule_address(char *domain, const char *domain_address);
static struct dns_domain_rule *_config_domain_rule_get(const char *domain);
static void *_new_dns_rule(enum domain_rule domain_rule)
static void *_new_dns_rule_ext(enum domain_rule domain_rule, int ext_size)
{
struct dns_rule *rule;
int size = 0;
@@ -220,6 +224,7 @@ static void *_new_dns_rule(enum domain_rule domain_rule)
return NULL;
}
size += ext_size;
rule = malloc(size);
if (!rule) {
return NULL;
@@ -230,6 +235,11 @@ static void *_new_dns_rule(enum domain_rule domain_rule)
return rule;
}
static void *_new_dns_rule(enum domain_rule domain_rule)
{
return _new_dns_rule_ext(domain_rule, 0);
}
static void _dns_rule_get(struct dns_rule *rule)
{
atomic_inc(&rule->refcnt);
@@ -480,6 +490,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
unsigned char *spki = NULL;
int drop_packet_latency_ms = 0;
int is_bootstrap_dns = 0;
int is_hostip_set = 0;
int ttl = 0;
/* clang-format off */
@@ -502,6 +513,8 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
{"set-mark", required_argument, NULL, 254}, /* set mark */
{"bootstrap-dns", no_argument, NULL, 255}, /* set as bootstrap dns */
{"subnet", required_argument, NULL, 256}, /* set subnet */
{"hitchhiking", no_argument, NULL, 257}, /* hitchhiking */
{"host-ip", required_argument, NULL, 258}, /* host ip */
{NULL, no_argument, NULL, 0}
};
/* clang-format on */
@@ -641,6 +654,17 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
_conf_client_subnet(optarg, &server->ipv4_ecs, &server->ipv6_ecs);
break;
}
case 257: {
server_flag |= SERVER_FLAG_HITCHHIKING;
break;
}
case 258: {
if (check_is_ipaddr(server->server) != 0) {
_conf_domain_rule_address(server->server, optarg);
is_hostip_set = 1;
}
break;
}
default:
break;
}
@@ -651,6 +675,18 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
safe_strncpy(server->tls_host_verify, server->server, DNS_MAX_CNAME_LEN);
}
/* update address rules for host-ip */
if (is_hostip_set == 1) {
struct dns_domain_rule *rule = _config_domain_rule_get(server->server);
if (rule) {
if (rule->rules[DOMAIN_RULE_ADDRESS_IPV4] != NULL && rule->rules[DOMAIN_RULE_ADDRESS_IPV6] == NULL) {
_conf_domain_rule_address(server->server, "#6");
} else if (rule->rules[DOMAIN_RULE_ADDRESS_IPV4] == NULL && rule->rules[DOMAIN_RULE_ADDRESS_IPV6] != NULL) {
_conf_domain_rule_address(server->server, "#4");
}
}
}
/* add new server */
server->type = type;
server->port = port;
@@ -763,7 +799,7 @@ static int _config_domain_rule_each_from_list(const char *file, domain_set_rule_
line_no = 0;
while (fgets(line, MAX_LINE_LEN, fp)) {
line_no++;
filed_num = sscanf(line, "%256s", domain);
filed_num = sscanf(line, "%255s", domain);
if (filed_num <= 0) {
continue;
}
@@ -827,6 +863,23 @@ static int _config_domain_rule_add_callback(const char *domain, void *priv)
return _config_domain_rule_add(domain, args->type, args->rule);
}
static struct dns_domain_rule *_config_domain_rule_get(const char *domain)
{
char domain_key[DNS_MAX_CONF_CNAME_LEN];
int len = 0;
len = strlen(domain);
if (len >= (int)sizeof(domain_key) - 2) {
return NULL;
}
reverse_string(domain_key, domain, len, 1);
domain_key[len] = '.';
len++;
domain_key[len] = 0;
return art_search(&dns_conf_domain_rule, (unsigned char *)domain_key, len);
}
static int _config_domain_rule_add(const char *domain, enum domain_rule type, void *rule)
{
struct dns_domain_rule *domain_rule = NULL;
@@ -835,14 +888,21 @@ static int _config_domain_rule_add(const char *domain, enum domain_rule type, vo
char domain_key[DNS_MAX_CONF_CNAME_LEN];
int len = 0;
int sub_rule_only = 0;
int root_rule_only = 0;
/* Reverse string, for suffix match */
len = strlen(domain);
if (len >= (int)sizeof(domain_key)) {
if (len >= (int)sizeof(domain_key) - 2) {
tlog(TLOG_ERROR, "domain name %s too long", domain);
goto errout;
}
if (len <= 0) {
tlog(TLOG_ERROR, "domain name %s too short", domain);
goto errout;
}
if (strncmp(domain, "domain-set:", sizeof("domain-set:") - 1) == 0) {
struct dns_set_rule_add_callback_args args;
args.type = type;
@@ -852,8 +912,23 @@ static int _config_domain_rule_add(const char *domain, enum domain_rule type, vo
}
reverse_string(domain_key, domain, len, 1);
if (domain[0] == '*') {
/* prefix wildcard */
len--;
if (domain[1] == '.') {
sub_rule_only = 1;
}
} else if (domain[0] == '-') {
/* root match only */
len--;
if (domain[1] == '.') {
root_rule_only = 1;
}
} else {
/* suffix match */
domain_key[len] = '.';
len++;
}
domain_key[len] = 0;
if (type >= DOMAIN_RULE_MAX) {
@@ -878,6 +953,8 @@ static int _config_domain_rule_add(const char *domain, enum domain_rule type, vo
}
domain_rule->rules[type] = rule;
domain_rule->sub_rule_only = sub_rule_only;
domain_rule->root_rule_only = root_rule_only;
_dns_rule_get(rule);
/* update domain rule */
@@ -1498,19 +1575,43 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
struct dns_rule_address_IPV4 *address_ipv4 = NULL;
struct dns_rule_address_IPV6 *address_ipv6 = NULL;
struct dns_rule *address = NULL;
char ip[MAX_IP_LEN];
int port = 0;
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
enum domain_rule type = 0;
unsigned int flag = 0;
char *ptr = NULL;
char *field = NULL;
char tmpbuff[TMP_BUFF_LEN] = {0};
if (*(domain_address) == '#') {
if (strncmp(domain_address, "#4", sizeof("#4")) == 0) {
char ipv6_addr[DNS_MAX_REPLY_IP_NUM][DNS_RR_AAAA_LEN];
int ipv6_num = 0;
char ipv4_addr[DNS_MAX_REPLY_IP_NUM][DNS_RR_A_LEN];
int ipv4_num = 0;
safe_strncpy(tmpbuff, domain_address, sizeof(tmpbuff));
ptr = tmpbuff;
do {
field = ptr;
ptr = strstr(ptr, ",");
if (field == NULL || *field == '\0') {
break;
}
if (ptr) {
*ptr = 0;
}
if (*(field) == '#') {
if (strncmp(field, "#4", sizeof("#4")) == 0) {
flag = DOMAIN_FLAG_ADDR_IPV4_SOA;
} else if (strncmp(domain_address, "#6", sizeof("#6")) == 0) {
} else if (strncmp(field, "#6", sizeof("#6")) == 0) {
flag = DOMAIN_FLAG_ADDR_IPV6_SOA;
} else if (strncmp(domain_address, "#", sizeof("#")) == 0) {
} else if (strncmp(field, "#", sizeof("#")) == 0) {
flag = DOMAIN_FLAG_ADDR_SOA;
} else {
goto errout;
@@ -1521,13 +1622,13 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
goto errout;
}
return 0;
} else if (*(domain_address) == '-') {
if (strncmp(domain_address, "-4", sizeof("-4")) == 0) {
continue;
} else if (*(field) == '-') {
if (strncmp(field, "-4", sizeof("-4")) == 0) {
flag = DOMAIN_FLAG_ADDR_IPV4_IGN;
} else if (strncmp(domain_address, "-6", sizeof("-6")) == 0) {
} else if (strncmp(field, "-6", sizeof("-6")) == 0) {
flag = DOMAIN_FLAG_ADDR_IPV6_IGN;
} else if (strncmp(domain_address, "-", sizeof("-")) == 0) {
} else if (strncmp(field, "-", sizeof("-")) == 0) {
flag = DOMAIN_FLAG_ADDR_IGN;
} else {
goto errout;
@@ -1538,13 +1639,15 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
goto errout;
}
return 0;
} else {
continue;
}
/* set address to domain */
if (parse_ip(domain_address, ip, &port) != 0) {
if (parse_ip(field, ip, &port) != 0) {
goto errout;
}
addr_len = sizeof(addr);
if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
goto errout;
}
@@ -1552,60 +1655,80 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
switch (addr.ss_family) {
case AF_INET: {
struct sockaddr_in *addr_in = NULL;
address_ipv4 = _new_dns_rule(DOMAIN_RULE_ADDRESS_IPV4);
if (address_ipv4 == NULL) {
goto errout;
}
addr_in = (struct sockaddr_in *)&addr;
memcpy(address_ipv4->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
type = DOMAIN_RULE_ADDRESS_IPV4;
address = (struct dns_rule *)address_ipv4;
if (ipv4_num < DNS_MAX_REPLY_IP_NUM) {
memcpy(ipv4_addr[ipv4_num], &addr_in->sin_addr.s_addr, DNS_RR_A_LEN);
ipv4_num++;
}
} 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)) {
address_ipv4 = _new_dns_rule(DOMAIN_RULE_ADDRESS_IPV4);
if (address_ipv4 == NULL) {
goto errout;
}
memcpy(address_ipv4->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
type = DOMAIN_RULE_ADDRESS_IPV4;
address = (struct dns_rule *)address_ipv4;
} else {
address_ipv6 = _new_dns_rule(DOMAIN_RULE_ADDRESS_IPV6);
if (address_ipv6 == NULL) {
goto errout;
}
memcpy(address_ipv6->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
type = DOMAIN_RULE_ADDRESS_IPV6;
address = (struct dns_rule *)address_ipv6;
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr) && ipv4_num < DNS_MAX_REPLY_IP_NUM) {
memcpy(ipv4_addr[ipv4_num], addr_in6->sin6_addr.s6_addr + 12, DNS_RR_A_LEN);
ipv4_num++;
} else if (ipv6_num < DNS_MAX_REPLY_IP_NUM) {
memcpy(ipv6_addr[ipv6_num], addr_in6->sin6_addr.s6_addr, DNS_RR_AAAA_LEN);
ipv6_num++;
}
} break;
default:
goto errout;
ip[0] = '\0';
break;
}
/* add PTR */
if (dns_conf_expand_ptr_from_address == 1 && _conf_ptr_add(domain, ip, 0) != 0) {
if (dns_conf_expand_ptr_from_address == 1 && ip[0] != '\0' && _conf_ptr_add(domain, ip, 0) != 0) {
goto errout;
}
if (ptr) {
ptr++;
}
} while (ptr);
if (ipv4_num > 0) {
address_ipv4 = _new_dns_rule_ext(DOMAIN_RULE_ADDRESS_IPV4, ipv4_num * DNS_RR_A_LEN);
if (address_ipv4 == NULL) {
goto errout;
}
/* add domain to ART-tree */
if (_config_domain_rule_add(domain, type, address) != 0) {
memcpy(address_ipv4->ipv4_addr, ipv4_addr[0], ipv4_num * DNS_RR_A_LEN);
address_ipv4->addr_num = ipv4_num;
address = (struct dns_rule *)address_ipv4;
if (_config_domain_rule_add(domain, DOMAIN_RULE_ADDRESS_IPV4, address) != 0) {
goto errout;
}
_dns_rule_put(address);
}
if (ipv6_num > 0) {
address_ipv6 = _new_dns_rule_ext(DOMAIN_RULE_ADDRESS_IPV6, ipv6_num * DNS_RR_AAAA_LEN);
if (address_ipv6 == NULL) {
goto errout;
}
memcpy(address_ipv6->ipv6_addr, ipv6_addr[0], ipv6_num * DNS_RR_AAAA_LEN);
address_ipv6->addr_num = ipv6_num;
address = (struct dns_rule *)address_ipv6;
if (_config_domain_rule_add(domain, DOMAIN_RULE_ADDRESS_IPV6, address) != 0) {
goto errout;
}
_dns_rule_put(address);
}
return 0;
errout:
if (address) {
_dns_rule_put(address);
}
tlog(TLOG_ERROR, "add address %s, %s failed", domain, domain_address);
tlog(TLOG_ERROR, "add address %s, %s at %s:%d failed", domain, domain_address, conf_get_conf_file(),
conf_get_current_lineno());
return 0;
}
@@ -2382,8 +2505,8 @@ static int _config_iplist_rule(char *subnet, enum address_rule rule)
static int _config_qtype_soa(void *data, int argc, char *argv[])
{
struct dns_qtype_soa_list *soa_list = NULL;
int i = 0;
int j = 0;
if (argc <= 1) {
return -1;
@@ -2393,19 +2516,31 @@ static int _config_qtype_soa(void *data, int argc, char *argv[])
char sub_arg[1024];
safe_strncpy(sub_arg, argv[i], sizeof(sub_arg));
for (char *tok = strtok(sub_arg, ","); tok; tok = strtok(NULL, ",")) {
soa_list = malloc(sizeof(*soa_list));
if (soa_list == NULL) {
tlog(TLOG_ERROR, "cannot malloc memory");
return -1;
char *dash = strstr(tok, "-");
if (dash != NULL) {
*dash = '\0';
}
memset(soa_list, 0, sizeof(*soa_list));
soa_list->qtypeid = atol(tok);
if (soa_list->qtypeid == DNS_T_AAAA) {
dns_conf_force_AAAA_SOA = 1;
long start = atol(tok);
long end = start;
if (start > MAX_QTYPE_NUM || start < 0) {
tlog(TLOG_ERROR, "invalid qtype %ld", start);
continue;
}
if (dash != NULL && *(dash + 1) != '\0') {
end = atol(dash + 1);
if (end > MAX_QTYPE_NUM) {
end = MAX_QTYPE_NUM;
}
}
for (j = start; j <= end; j++) {
int offset = j / 8;
int bit = j % 8;
dns_qtype_soa_table[offset] |= (1 << bit);
}
uint32_t key = hash_32_generic(soa_list->qtypeid, 32);
hash_add(dns_qtype_soa_table.qtype, &soa_list->node, key);
}
}
@@ -2414,14 +2549,9 @@ static int _config_qtype_soa(void *data, int argc, char *argv[])
static void _config_qtype_soa_table_destroy(void)
{
struct dns_qtype_soa_list *soa_list = NULL;
struct hlist_node *tmp = NULL;
unsigned long i = 0;
hash_for_each_safe(dns_qtype_soa_table.qtype, i, tmp, soa_list, node)
{
hlist_del_init(&soa_list->node);
free(soa_list);
if (dns_qtype_soa_table) {
free(dns_qtype_soa_table);
dns_qtype_soa_table = NULL;
}
}
@@ -2502,9 +2632,6 @@ static int _conf_client_subnet(char *subnet, struct dns_edns_client_subnet *ipv4
*slash = 0;
slash++;
subnet_len = atoi(slash);
if (subnet_len < 0 || subnet_len > 128) {
return -1;
}
}
if (getaddr_by_host(str_subnet, (struct sockaddr *)&addr, &addr_len) != 0) {
@@ -2513,9 +2640,23 @@ static int _conf_client_subnet(char *subnet, struct dns_edns_client_subnet *ipv4
switch (addr.ss_family) {
case AF_INET:
if (subnet_len < 0 || subnet_len > 32) {
return -1;
}
if (subnet_len == 0) {
subnet_len = 32;
}
ecs = ipv4_ecs;
break;
case AF_INET6:
if (subnet_len < 0 || subnet_len > 128) {
return -1;
}
if (subnet_len == 0) {
subnet_len = 128;
}
ecs = ipv6_ecs;
break;
default:
@@ -2700,6 +2841,18 @@ errout:
return -1;
}
static int _conf_ddns_domain(void *data, int argc, char *argv[])
{
if (argc <= 1) {
tlog(TLOG_ERROR, "invalid parameter.");
return -1;
}
const char *domain = argv[1];
_config_domain_rule_flag_set(domain, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0);
return 0;
}
static int _conf_domain_rule_rr_ttl(const char *domain, int ttl, int ttl_min, int ttl_max)
{
struct dns_ttl_rule *rr_ttl = NULL;
@@ -3198,7 +3351,7 @@ static int _conf_dhcp_lease_dnsmasq_add(const char *file)
line_no = 0;
while (fgets(line, MAX_LINE_LEN, fp)) {
line_no++;
filed_num = sscanf(line, "%*s %*s %64s %256s %*s", ip, hostname);
filed_num = sscanf(line, "%*s %*s %63s %255s %*s", ip, hostname);
if (filed_num <= 0) {
continue;
}
@@ -3443,12 +3596,15 @@ static struct config_item _config_item[] = {
CONF_CUSTOM("edns-client-subnet", _conf_edns_client_subnet, NULL),
CONF_CUSTOM("domain-rules", _conf_domain_rules, NULL),
CONF_CUSTOM("domain-set", _conf_domain_set, NULL),
CONF_CUSTOM("ddns-domain", _conf_ddns_domain, NULL),
CONF_CUSTOM("dnsmasq-lease-file", _conf_dhcp_lease_dnsmasq_file, NULL),
CONF_CUSTOM("hosts-file", _conf_hosts_file, NULL),
CONF_STRING("ca-file", (char *)&dns_conf_ca_file, DNS_MAX_PATH),
CONF_STRING("ca-path", (char *)&dns_conf_ca_path, DNS_MAX_PATH),
CONF_STRING("user", (char *)&dns_conf_user, sizeof(dns_conf_user)),
CONF_YESNO("debug-save-fail-packet", &dns_save_fail_packet),
CONF_YESNO("no-pidfile", &dns_no_pidfile),
CONF_YESNO("no-daemon", &dns_no_daemon),
CONF_STRING("resolv-file", (char *)&dns_resolv_file, sizeof(dns_resolv_file)),
CONF_STRING("debug-save-fail-packet-dir", (char *)&dns_save_fail_packet_dir, sizeof(dns_save_fail_packet_dir)),
CONF_CUSTOM("conf-file", config_additional_file, NULL),
@@ -3530,7 +3686,12 @@ static int _dns_server_load_conf_init(void)
hash_init(dns_ipset_table.ipset);
hash_init(dns_nftset_table.nftset);
hash_init(dns_qtype_soa_table.qtype);
dns_qtype_soa_table = malloc(MAX_QTYPE_NUM / 8 + 1);
if (dns_qtype_soa_table == NULL) {
tlog(TLOG_WARN, "malloc qtype soa table failed.");
return -1;
}
memset(dns_qtype_soa_table, 0, MAX_QTYPE_NUM / 8 + 1);
hash_init(dns_group_table.group);
hash_init(dns_hosts_table.hosts);
hash_init(dns_ptr_table.ptr);

View File

@@ -57,6 +57,9 @@ extern "C" {
#define DEFAULT_DNS_TLS_PORT 853
#define DEFAULT_DNS_HTTPS_PORT 443
#define DNS_MAX_CONF_CNAME_LEN 256
#define MAX_QTYPE_NUM 65535
#define DNS_MAX_REPLY_IP_NUM 8
#define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
#define SMARTDNS_LOG_FILE "/var/log/smartdns/smartdns.log"
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns/smartdns-audit.log"
@@ -116,6 +119,7 @@ typedef enum {
#define DOMAIN_FLAG_NO_CACHE (1 << 17)
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
#define SERVER_FLAG_HITCHHIKING (1 << 1)
#define BIND_FLAG_NO_RULE_ADDR (1 << 0)
#define BIND_FLAG_NO_RULE_NAMESERVER (1 << 1)
@@ -148,12 +152,14 @@ struct dns_rule_flags {
struct dns_rule_address_IPV4 {
struct dns_rule head;
unsigned char ipv4_addr[DNS_RR_A_LEN];
char addr_num;
unsigned char ipv4_addr[][DNS_RR_A_LEN];
};
struct dns_rule_address_IPV6 {
struct dns_rule head;
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
char addr_num;
unsigned char ipv6_addr[][DNS_RR_AAAA_LEN];
};
struct dns_ipset_name {
@@ -212,8 +218,9 @@ extern struct dns_nftset_names dns_conf_nftset_no_speed;
struct dns_domain_rule {
struct dns_rule head;
unsigned char sub_rule_only : 1;
unsigned char root_rule_only : 1;
struct dns_rule *rules[DOMAIN_RULE_MAX];
int is_sub_rule[DOMAIN_RULE_MAX];
};
struct dns_nameserver_rule {
@@ -381,15 +388,7 @@ struct dns_bind_ip {
struct nftset_ipset_rules nftset_ipset_rule;
};
struct dns_qtype_soa_list {
struct hlist_node node;
uint32_t qtypeid;
};
struct dns_qtype_soa_table {
DECLARE_HASHTABLE(qtype, 8);
};
extern struct dns_qtype_soa_table dns_qtype_soa_table;
extern uint8_t *dns_qtype_soa_table;
struct dns_domain_set_rule {
struct list_head list;
@@ -520,6 +519,9 @@ extern int dns_save_fail_packet;
extern char dns_save_fail_packet_dir[DNS_MAX_PATH];
extern char dns_resolv_file[DNS_MAX_PATH];
extern int dns_no_pidfile;
extern int dns_no_daemon;
void dns_server_load_exit(void);
int dns_server_load_conf(const char *file);

View File

@@ -128,6 +128,7 @@ struct dns_server_post_context {
struct dns_request *request;
struct dns_packet *packet;
int ip_num;
const unsigned char *ip_addr[MAX_IP_NUM];
dns_type_t qtype;
int do_cache;
int do_reply;
@@ -215,6 +216,11 @@ struct dns_request_pending_list {
struct hlist_node node;
};
struct dns_request_domain_rule {
struct dns_rule *rules[DOMAIN_RULE_MAX];
int is_sub_rule[DOMAIN_RULE_MAX];
};
typedef DNS_CHILD_POST_RESULT (*child_request_callback)(struct dns_request *request, struct dns_request *child_request,
int is_first_resp);
@@ -272,6 +278,7 @@ struct dns_request {
struct dns_soa soa;
int has_soa;
int force_soa;
atomic_t notified;
atomic_t do_callback;
@@ -302,7 +309,7 @@ struct dns_request {
atomic_t ip_map_num;
DECLARE_HASHTABLE(ip_map, 4);
struct dns_domain_rule domain_rule;
struct dns_request_domain_rule domain_rule;
int skip_domain_rule;
struct dns_domain_check_orders *check_order_list;
int check_order;
@@ -630,6 +637,15 @@ static void _dns_server_post_context_init(struct dns_server_post_context *contex
context->request = request;
}
static void _dns_server_context_add_ip(struct dns_server_post_context *context, const unsigned char *ip_addr)
{
if (context->ip_num < MAX_IP_NUM) {
context->ip_addr[context->ip_num] = ip_addr;
}
context->ip_num++;
}
static void _dns_server_post_context_init_from(struct dns_server_post_context *context, struct dns_request *request,
struct dns_packet *packet, unsigned char *inpacket, int inpacket_len)
{
@@ -709,7 +725,7 @@ static void _dns_server_audit_log(struct dns_server_post_context *context)
return;
}
for (j = 1; j < DNS_RRS_END && context->packet; j++) {
for (j = 1; j < DNS_RRS_OPT && context->packet; j++) {
rrs = dns_get_rrs_start(context->packet, j, &rr_count);
for (i = 0; i < rr_count && rrs && left_len > 0; i++, rrs = dns_get_rrs_next(context->packet, rrs)) {
switch (rrs->type) {
@@ -894,7 +910,7 @@ static int _dns_rrs_add_all_best_ip(struct dns_server_post_context *context)
}
}
context->ip_num++;
_dns_server_context_add_ip(context, addr_map->ip_addr);
if (addr_map->addr_type == DNS_T_A) {
ret |= dns_add_A(context->packet, DNS_RRS_AN, domain, request->ip_ttl, addr_map->ip_addr);
} else if (addr_map->addr_type == DNS_T_AAAA) {
@@ -947,7 +963,7 @@ static int _dns_add_rrs(struct dns_server_post_context *context)
/* add A record */
if (request->has_ip && context->do_force_soa == 0) {
context->ip_num++;
_dns_server_context_add_ip(context, request->ip_addr);
if (context->qtype == DNS_T_A) {
ret |= dns_add_A(context->packet, DNS_RRS_AN, domain, request->ip_ttl, request->ip_addr);
tlog(TLOG_DEBUG, "result: %s, rtt: %.1f ms, %d.%d.%d.%d", request->domain, ((float)request->ping_time) / 10,
@@ -1338,7 +1354,7 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
return -1;
}
for (j = 1; j < DNS_RRS_END && context->packet; j++) {
for (j = 1; j < DNS_RRS_OPT && context->packet; j++) {
rrs = dns_get_rrs_start(context->packet, j, &rr_count);
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(context->packet, rrs)) {
switch (rrs->type) {
@@ -1486,21 +1502,9 @@ errout:
return -1;
}
static int _dns_result_callback_nxdomain(struct dns_request *request)
{
char ip[DNS_MAX_CNAME_LEN];
unsigned int ping_time = -1;
ip[0] = 0;
if (request->result_callback == NULL) {
return 0;
}
return request->result_callback(request->domain, request->rcode, request->qtype, ip, ping_time, request->user_ptr);
}
static int _dns_result_callback(struct dns_server_post_context *context)
{
struct dns_result result;
char ip[DNS_MAX_CNAME_LEN];
unsigned int ping_time = -1;
struct dns_request *request = context->request;
@@ -1513,38 +1517,36 @@ static int _dns_result_callback(struct dns_server_post_context *context)
return 0;
}
if (request->has_soa || context->do_force_soa || context->ip_num == 0) {
goto out;
}
if (request->has_ip == 0) {
goto out;
}
ip[0] = 0;
memset(&result, 0, sizeof(result));
ping_time = request->ping_time;
if (request->qtype == DNS_T_A) {
result.domain = request->domain;
result.rtcode = request->rcode;
result.addr_type = request->qtype;
result.ip = ip;
result.has_soa = request->has_soa | context->do_force_soa;
result.ping_time = ping_time;
result.ip_num = 0;
sprintf(ip, "%d.%d.%d.%d", request->ip_addr[0], request->ip_addr[1], request->ip_addr[2], request->ip_addr[3]);
return request->result_callback(request->domain, request->rcode, request->qtype, ip, ping_time,
request->user_ptr);
if (request->has_ip != 0 && context->do_force_soa == 0) {
for (int i = 0; i < context->ip_num && i < MAX_IP_NUM; i++) {
result.ip_addr[i] = context->ip_addr[i];
result.ip_num++;
}
if (request->qtype == DNS_T_A) {
sprintf(ip, "%d.%d.%d.%d", request->ip_addr[0], request->ip_addr[1], request->ip_addr[2],
request->ip_addr[3]);
} else if (request->qtype == DNS_T_AAAA) {
sprintf(ip, "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->ip_addr[0],
request->ip_addr[1], request->ip_addr[2], request->ip_addr[3], request->ip_addr[4], request->ip_addr[5],
request->ip_addr[6], request->ip_addr[7], request->ip_addr[8], request->ip_addr[9],
request->ip_addr[10], request->ip_addr[11], request->ip_addr[12], request->ip_addr[13],
request->ip_addr[14], request->ip_addr[15]);
return request->result_callback(request->domain, request->rcode, request->qtype, ip, ping_time,
request->user_ptr);
request->ip_addr[1], request->ip_addr[2], request->ip_addr[3], request->ip_addr[4],
request->ip_addr[5], request->ip_addr[6], request->ip_addr[7], request->ip_addr[8],
request->ip_addr[9], request->ip_addr[10], request->ip_addr[11], request->ip_addr[12],
request->ip_addr[13], request->ip_addr[14], request->ip_addr[15]);
}
}
_dns_result_callback_nxdomain(request);
return 0;
out:
_dns_result_callback_nxdomain(request);
return 0;
return request->result_callback(&result, request->user_ptr);
}
static int _dns_cache_specify_packet(struct dns_server_post_context *context)
@@ -1710,7 +1712,7 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
timeout_value = _dns_server_get_conf_ttl(request, 0) * 3;
}
for (j = 1; j < DNS_RRS_END; j++) {
for (j = 1; j < DNS_RRS_OPT; j++) {
rrs = dns_get_rrs_start(context->packet, j, &rr_count);
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(context->packet, rrs)) {
switch (rrs->type) {
@@ -1838,7 +1840,7 @@ static int _dns_request_update_id_ttl(struct dns_server_post_context *context)
}
if (ttl > dns_conf_rr_ttl_reply_max) {
ttl %= dns_conf_rr_ttl_reply_max;
ttl = dns_conf_rr_ttl_reply_max;
}
if (ttl == 0) {
@@ -2136,7 +2138,7 @@ out:
_dns_server_post_context_init(&context, request);
context.do_cache = 1;
context.do_ipset = 1;
context.do_force_soa = request->dualstack_selection_force_soa;
context.do_force_soa = request->dualstack_selection_force_soa | request->force_soa;
context.do_audit = 1;
context.do_reply = 1;
context.reply_ttl = _dns_server_get_reply_ttl(request, ttl);
@@ -2154,7 +2156,7 @@ static int _dns_server_request_complete(struct dns_request *request)
}
static int _dns_ip_address_check_add(struct dns_request *request, char *cname, unsigned char *addr,
dns_type_t addr_type, int ping_time)
dns_type_t addr_type, int ping_time, struct dns_ip_address **out_addr_map)
{
uint32_t key = 0;
struct dns_ip_address *addr_map = NULL;
@@ -2213,6 +2215,10 @@ static int _dns_ip_address_check_add(struct dns_request *request, char *cname, u
hash_add(request->ip_map, &addr_map->node, key);
pthread_mutex_unlock(&request->ip_map_lock);
if (out_addr_map != NULL) {
*out_addr_map = addr_map;
}
return 0;
}
@@ -2355,7 +2361,7 @@ static void _dns_server_complete_with_multi_ipaddress(struct dns_request *reques
context.do_log_result = 1;
context.select_all_best_ip = 1;
context.skip_notify_count = 1;
context.do_force_soa = request->dualstack_selection_force_soa;
context.do_force_soa = request->dualstack_selection_force_soa | request->force_soa;
_dns_request_post(&context);
_dns_server_reply_all_pending_list(request, &context);
}
@@ -2762,8 +2768,9 @@ static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char
if (rule->bogus) {
request->rcode = DNS_RC_NXDOMAIN;
request->has_soa = 1;
request->force_soa = 1;
_dns_server_setup_soa(request);
goto match;
goto nxdomain;
}
/* blacklist-ip */
@@ -2791,6 +2798,8 @@ rule_not_found:
return -1;
skip:
return -2;
nxdomain:
return -3;
match:
if (request->rcode == DNS_RC_SERVFAIL) {
request->rcode = DNS_RC_NXDOMAIN;
@@ -2848,10 +2857,10 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
/* match */
_dns_server_request_release(request);
return -1;
} else if (ip_check_result == -2) {
/* skip */
} else if (ip_check_result == -2 || ip_check_result == -3) {
/* skip, nxdomain */
_dns_server_request_release(request);
return -2;
return ip_check_result;
}
if (atomic_read(&request->ip_map_num) == 0) {
@@ -2879,7 +2888,7 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
}
/* add this ip to request */
if (_dns_ip_address_check_add(request, cname, addr, DNS_T_A, 0) != 0) {
if (_dns_ip_address_check_add(request, cname, addr, DNS_T_A, 0, NULL) != 0) {
_dns_server_request_release(request);
return -1;
}
@@ -2925,10 +2934,10 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
/* match */
_dns_server_request_release(request);
return -1;
} else if (ip_check_result == -2) {
/* skip */
} else if (ip_check_result == -2 || ip_check_result == -3) {
/* skip, nxdomain */
_dns_server_request_release(request);
return -2;
return ip_check_result;
}
if (atomic_read(&request->ip_map_num) == 0) {
@@ -2956,7 +2965,7 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
}
/* add this ip to request */
if (_dns_ip_address_check_add(request, cname, addr, DNS_T_AAAA, 0) != 0) {
if (_dns_ip_address_check_add(request, cname, addr, DNS_T_AAAA, 0, NULL) != 0) {
_dns_server_request_release(request);
return -1;
}
@@ -3000,7 +3009,7 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
request->rcode = packet->head.rcode;
}
for (j = 1; j < DNS_RRS_END; j++) {
for (j = 1; j < DNS_RRS_OPT; j++) {
rrs = dns_get_rrs_start(packet, j, &rr_count);
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
switch (rrs->type) {
@@ -3010,6 +3019,8 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
break;
} else if (ret == -2) {
continue;
} else if (ret == -3) {
return -1;
}
request->rcode = packet->head.rcode;
} break;
@@ -3019,6 +3030,8 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
break;
} else if (ret == -2) {
continue;
} else if (ret == -3) {
return -1;
}
request->rcode = packet->head.rcode;
} break;
@@ -3064,7 +3077,7 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
}
} break;
default:
tlog(TLOG_DEBUG, "%s, qtype: %d", name, rrs->type);
tlog(TLOG_DEBUG, "%s, qtype: %d, rrstype = %d", name, rrs->type, j);
break;
}
}
@@ -3100,7 +3113,7 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
request->rcode = packet->head.rcode;
}
for (j = 1; j < DNS_RRS_END; j++) {
for (j = 1; j < DNS_RRS_OPT; j++) {
rrs = dns_get_rrs_start(packet, j, &rr_count);
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
switch (rrs->type) {
@@ -3128,12 +3141,8 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
/* ip rule check */
ip_check_result = _dns_server_ip_rule_check(request, addr, 4, DNS_T_A, result_flag);
if (ip_check_result == 0) {
/* match */
_dns_server_request_release(request);
return 0;
} else if (ip_check_result == -2) {
/* skip */
if (ip_check_result == 0 || ip_check_result == -2 || ip_check_result == -3) {
/* match, skip, nxdomain */
_dns_server_request_release(request);
return 0;
}
@@ -3172,12 +3181,8 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
ip_check_result = _dns_server_ip_rule_check(request, addr, 16, DNS_T_AAAA, result_flag);
if (ip_check_result == 0) {
/* match */
_dns_server_request_release(request);
return 0;
} else if (ip_check_result == -2) {
/* skip */
if (ip_check_result == 0 || ip_check_result == -2 || ip_check_result == -3) {
/* match, skip, nxdomain */
_dns_server_request_release(request);
return 0;
}
@@ -3226,13 +3231,14 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
struct dns_request *request = context->request;
struct dns_packet *packet = context->packet;
for (j = 1; j < DNS_RRS_END; j++) {
for (j = 1; j < DNS_RRS_OPT; j++) {
rrs = dns_get_rrs_start(packet, j, &rr_count);
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
switch (rrs->type) {
case DNS_T_A: {
unsigned char addr[4];
char name[DNS_MAX_CNAME_LEN] = {0};
struct dns_ip_address *addr_map = NULL;
if (request->qtype != DNS_T_A) {
continue;
@@ -3247,11 +3253,11 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
}
if (context->no_check_add_ip == 0 &&
_dns_ip_address_check_add(request, name, addr, DNS_T_A, request->ping_time) != 0) {
_dns_ip_address_check_add(request, name, addr, DNS_T_A, request->ping_time, &addr_map) != 0) {
continue;
}
context->ip_num++;
_dns_server_context_add_ip(context, addr_map->ip_addr);
if (request->has_ip == 1) {
continue;
}
@@ -3265,6 +3271,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
case DNS_T_AAAA: {
unsigned char addr[16];
char name[DNS_MAX_CNAME_LEN] = {0};
struct dns_ip_address *addr_map = NULL;
if (request->qtype != DNS_T_AAAA) {
/* ignore non-matched query type */
@@ -3278,11 +3285,11 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
}
if (context->no_check_add_ip == 0 &&
_dns_ip_address_check_add(request, name, addr, DNS_T_AAAA, request->ping_time) != 0) {
_dns_ip_address_check_add(request, name, addr, DNS_T_AAAA, request->ping_time, &addr_map) != 0) {
continue;
}
context->ip_num++;
_dns_server_context_add_ip(context, addr_map->ip_addr);
if (request->has_ip == 1) {
continue;
}
@@ -3395,7 +3402,7 @@ static void _dns_server_query_end(struct dns_request *request)
/* Not need to wait check result if only has one ip address */
if (ip_num <= 1 && request_wait == 1) {
if (request->dualstack_selection_query == 1) {
if ((dns_conf_ipset_no_speed.ipv4_enable || dns_conf_nftset_no_speed.ip6_enable ||
if ((dns_conf_ipset_no_speed.ipv4_enable || dns_conf_nftset_no_speed.ip_enable ||
dns_conf_ipset_no_speed.ipv6_enable || dns_conf_nftset_no_speed.ip6_enable) &&
dns_conf_dns_dns64.prefix_len == 0) {
/* if speed check fail enabled, we need reply quickly, otherwise wait for ping result.*/
@@ -3416,21 +3423,20 @@ out:
_dns_server_request_release(request);
}
static int dns_server_dualstack_callback(const char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip,
unsigned int ping_time, void *user_ptr)
static int dns_server_dualstack_callback(const struct dns_result *result, void *user_ptr)
{
struct dns_request *request = (struct dns_request *)user_ptr;
tlog(TLOG_DEBUG, "dualstack result: domain: %s, ip: %s, type: %d, ping: %d, rcode: %d", domain, ip, addr_type,
ping_time, rtcode);
tlog(TLOG_DEBUG, "dualstack result: domain: %s, ip: %s, type: %d, ping: %d, rcode: %d", result->domain, result->ip,
result->addr_type, result->ping_time, result->rtcode);
if (request == NULL) {
return -1;
}
if (rtcode == DNS_RC_NOERROR && ip[0] != 0) {
if (result->rtcode == DNS_RC_NOERROR && result->ip[0] != 0) {
request->dualstack_selection_has_ip = 1;
}
request->dualstack_selection_ping_time = ping_time;
request->dualstack_selection_ping_time = result->ping_time;
_dns_server_query_end(request);
@@ -3629,6 +3635,10 @@ static int _dns_server_get_inet_by_addr(struct sockaddr_storage *localaddr, stru
break;
}
if (ifa == NULL) {
goto errout;
}
freeifaddrs(ifaddr);
return 0;
errout:
@@ -3929,6 +3939,16 @@ static int _dns_server_get_rules(unsigned char *key, uint32_t key_len, int is_su
return 0;
}
/* only subkey rule */
if (domain_rule->sub_rule_only == 1 && is_subkey == 0) {
return 0;
}
/* only root key rule */
if (domain_rule->root_rule_only == 1 && is_subkey == 1) {
return 0;
}
for (i = 0; i < DOMAIN_RULE_MAX; i++) {
if (domain_rule->rules[i] == NULL) {
continue;
@@ -3964,6 +3984,10 @@ static void _dns_server_get_domain_rule_by_domain(struct dns_request *request, c
/* reverse domain string */
domain_len = strlen(domain);
if (domain_len >= (int)sizeof(domain_key) - 2) {
return;
}
reverse_string(domain_key, domain, domain_len, 1);
domain_key[domain_len] = '.';
domain_len++;
@@ -4114,10 +4138,35 @@ static int _dns_server_get_local_ttl(struct dns_request *request)
return DNS_SERVER_ADDR_TTL;
}
static int _dns_server_address_generate_order(int orders[], int order_num, int max_order_count)
{
int i = 0;
int j = 0;
int k = 0;
for (i = 0; i < order_num && i < max_order_count; i++) {
orders[i] = i;
}
for (i = 0; i < order_num && max_order_count; i++) {
k = rand() % order_num;
j = rand() % order_num;
if (j == k) {
continue;
}
int temp = orders[j];
orders[j] = orders[k];
orders[k] = temp;
}
return 0;
}
static int _dns_server_process_address(struct dns_request *request)
{
struct dns_rule_address_IPV4 *address_ipv4 = NULL;
struct dns_rule_address_IPV6 *address_ipv6 = NULL;
int orders[DNS_MAX_REPLY_IP_NUM];
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_ADDR) == 0) {
goto errout;
@@ -4130,14 +4179,39 @@ static int _dns_server_process_address(struct dns_request *request)
goto errout;
}
address_ipv4 = _dns_server_get_dns_rule(request, DOMAIN_RULE_ADDRESS_IPV4);
memcpy(request->ip_addr, address_ipv4->ipv4_addr, DNS_RR_A_LEN);
if (address_ipv4 == NULL) {
goto errout;
}
_dns_server_address_generate_order(orders, address_ipv4->addr_num, DNS_MAX_REPLY_IP_NUM);
memcpy(request->ip_addr, address_ipv4->ipv4_addr[orders[0]], DNS_RR_A_LEN);
for (int i = 1; i < address_ipv4->addr_num; i++) {
int index = orders[i];
if (index >= address_ipv4->addr_num) {
continue;
}
_dns_ip_address_check_add(request, request->cname, address_ipv4->ipv4_addr[index], DNS_T_A, 1, NULL);
}
break;
case DNS_T_AAAA:
if (request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV6] == NULL) {
goto errout;
}
address_ipv6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_ADDRESS_IPV6);
memcpy(request->ip_addr, address_ipv6->ipv6_addr, DNS_RR_AAAA_LEN);
if (address_ipv6 == NULL) {
goto errout;
}
_dns_server_address_generate_order(orders, address_ipv6->addr_num, DNS_MAX_REPLY_IP_NUM);
memcpy(request->ip_addr, address_ipv6->ipv6_addr[orders[0]], DNS_RR_AAAA_LEN);
for (int i = 1; i < address_ipv6->addr_num; i++) {
int index = orders[i];
if (index >= address_ipv6->addr_num) {
continue;
}
_dns_ip_address_check_add(request, request->cname, address_ipv6->ipv6_addr[index], DNS_T_AAAA, 1, NULL);
}
break;
default:
goto errout;
@@ -4153,6 +4227,7 @@ static int _dns_server_process_address(struct dns_request *request)
context.do_reply = 1;
context.do_audit = 1;
context.do_ipset = 1;
context.select_all_best_ip = 1;
_dns_request_post(&context);
return 0;
@@ -4284,7 +4359,7 @@ static int _dns_server_process_cname_pre(struct dns_request *request)
{
struct dns_cname_rule *cname = NULL;
struct dns_rule_flags *rule_flag = NULL;
struct dns_domain_rule domain_rule;
struct dns_request_domain_rule domain_rule;
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_CNAME) == 0) {
return 0;
@@ -4545,17 +4620,16 @@ errout:
static int _dns_server_qtype_soa(struct dns_request *request)
{
struct dns_qtype_soa_list *soa_list = NULL;
if (request->skip_qtype_soa) {
if (request->skip_qtype_soa || dns_qtype_soa_table == NULL) {
return -1;
}
uint32_t key = hash_32_generic(request->qtype, 32);
hash_for_each_possible(dns_qtype_soa_table.qtype, soa_list, node, key)
{
if (request->qtype != soa_list->qtypeid) {
continue;
if (request->qtype >= 0 && request->qtype <= MAX_QTYPE_NUM) {
int offset = request->qtype / 8;
int bit = request->qtype % 8;
if ((dns_qtype_soa_table[offset] & (1 << bit)) == 0) {
return -1;
}
}
_dns_server_reply_SOA(DNS_RC_NOERROR, request);
@@ -4563,9 +4637,6 @@ static int _dns_server_qtype_soa(struct dns_request *request)
return 0;
}
return -1;
}
static void _dns_server_process_speed_rule(struct dns_request *request)
{
struct dns_domain_check_orders *check_order = NULL;
@@ -5475,7 +5546,7 @@ int dns_server_query(const char *domain, int qtype, struct dns_server_query_opti
_dns_server_request_set_callback(request, callback, user_ptr);
ret = _dns_server_do_query(request, 0);
if (ret != 0) {
tlog(TLOG_ERROR, "do query %s failed.\n", domain);
tlog(TLOG_DEBUG, "do query %s failed.\n", domain);
goto errout;
}
@@ -6103,9 +6174,7 @@ static int _dns_server_process_tls(struct dns_server_conn_tls_client *tls_client
if (tls_client->status == DNS_SERVER_CLIENT_STATUS_CONNECTING) {
/* do SSL hand shake */
ret = _ssl_do_accept(tls_client);
if (ret == 0) {
goto errout;
} else if (ret < 0) {
if (ret <= 0) {
memset(&fd_event, 0, sizeof(fd_event));
ssl_ret = _ssl_get_error(tls_client, ret);
if (ssl_ret == SSL_ERROR_WANT_READ) {
@@ -6117,7 +6186,9 @@ static int _dns_server_process_tls(struct dns_server_conn_tls_client *tls_client
} else {
unsigned long ssl_err = ERR_get_error();
int ssl_reason = ERR_GET_REASON(ssl_err);
tlog(TLOG_DEBUG, "Handshake with %s failed, error no: %s(%d, %d, %d)\n", "",
char name[DNS_MAX_CNAME_LEN];
tlog(TLOG_DEBUG, "Handshake with %s failed, error no: %s(%d, %d, %d)\n",
get_host_by_addr(name, sizeof(name), (struct sockaddr *)&tls_client->addr),
ERR_reason_error_string(ssl_err), ret, ssl_ret, ssl_reason);
ret = 0;
goto errout;
@@ -6650,7 +6721,7 @@ static int _dns_create_socket(const char *host_ip, int type)
{
int fd = -1;
struct addrinfo *gai = NULL;
char port_str[8];
char port_str[16];
char ip[MAX_IP_LEN];
char host_ip_device[MAX_IP_LEN * 2];
int port = 0;

View File

@@ -49,9 +49,21 @@ void dns_server_stop(void);
void dns_server_exit(void);
#define MAX_IP_NUM 16
struct dns_result {
const char *domain;
dns_rtcode_t rtcode;
dns_type_t addr_type;
const char *ip;
const unsigned char *ip_addr[MAX_IP_NUM];
int ip_num;
int has_soa;
unsigned int ping_time;
};
/* query result notify function */
typedef int (*dns_result_callback)(const char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip,
unsigned int ping_time, void *user_ptr);
typedef int (*dns_result_callback)(const struct dns_result *result, void *user_ptr);
/* query domain */
int dns_server_query(const char *domain, int qtype, struct dns_server_query_option *server_query_option,

View File

@@ -726,7 +726,7 @@ static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
len = sendto(ping.fd_icmp6, &ping_host->packet, sizeof(struct fast_ping_packet), 0, &ping_host->addr,
ping_host->addr_len);
if (len < 0 || len != sizeof(struct fast_ping_packet)) {
if (len != sizeof(struct fast_ping_packet)) {
int err = errno;
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL || errno == EHOSTUNREACH) {
goto errout;
@@ -806,7 +806,7 @@ static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
len = sendto(ping.fd_icmp, packet, sizeof(struct fast_ping_packet), 0, &ping_host->addr, ping_host->addr_len);
if (len < 0 || len != sizeof(struct fast_ping_packet)) {
if (len != sizeof(struct fast_ping_packet)) {
int err = errno;
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL || errno == EPERM || errno == EACCES) {
goto errout;
@@ -858,7 +858,7 @@ static int _fast_ping_sendping_udp(struct ping_host_struct *ping_host)
gettimeofday(&ping_host->last, NULL);
len = sendto(fd, &dns_head, sizeof(dns_head), 0, &ping_host->addr, ping_host->addr_len);
if (len < 0 || len != sizeof(dns_head)) {
if (len != sizeof(dns_head)) {
int err = errno;
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL || errno == EPERM || errno == EACCES) {
goto errout;

View File

@@ -189,6 +189,8 @@ int load_conf(const char *file, struct config_item items[], conf_error_handler h
void load_exit(void);
int conf_get_current_lineno(void);
const char *conf_get_conf_file(void);
const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path_len);

View File

@@ -26,12 +26,18 @@
#include <unistd.h>
static const char *current_conf_file = NULL;
static int current_conf_lineno = 0;
const char *conf_get_conf_file(void)
{
return current_conf_file;
}
int conf_get_current_lineno(void)
{
return current_conf_lineno;
}
static char *get_dir_name(char *path)
{
if (strstr(path, "/") == NULL) {
@@ -347,6 +353,7 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
char value[MAX_LINE_LEN];
int filed_num = 0;
int i = 0;
int last_item_index = -1;
int argc = 0;
char *argv[1024];
int ret = 0;
@@ -354,6 +361,8 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
int line_no = 0;
int line_len = 0;
int read_len = 0;
int is_last_line_wrap = 0;
int current_line_wrap = 0;
const char *last_file = NULL;
if (handler == NULL) {
@@ -367,16 +376,46 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
line_no = 0;
while (fgets(line + line_len, MAX_LINE_LEN - line_len, fp)) {
current_line_wrap = 0;
line_no++;
read_len = strnlen(line + line_len, sizeof(line));
if (read_len >= 2 && *(line + line_len + read_len - 2) == '\\') {
line_len += read_len - 2;
line[line_len] = '\0';
read_len -= 1;
current_line_wrap = 1;
}
/* comment in wrap line, skip */
if (is_last_line_wrap && read_len > 0) {
if (*(line + line_len) == '#') {
continue;
}
line_len = 0;
}
filed_num = sscanf(line, "%63s %8192[^\r\n]s", key, value);
/* trim prefix spaces in wrap line */
if ((current_line_wrap == 1 || is_last_line_wrap == 1) && read_len > 0) {
is_last_line_wrap = current_line_wrap;
read_len -= 1;
for (i = 0; i < read_len; i++) {
char *ptr = line + line_len + i;
if (*ptr == ' ' || *ptr == '\t') {
continue;
}
memmove(line + line_len, ptr, read_len - i + 1);
line_len += read_len - i;
break;
}
line[line_len] = '\0';
if (current_line_wrap) {
continue;
}
}
line_len = 0;
is_last_line_wrap = 0;
filed_num = sscanf(line, "%63s %8191[^\r\n]s", key, value);
if (filed_num <= 0) {
continue;
}
@@ -392,13 +431,21 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
goto errout;
}
for (i = 0;; i++) {
for (i = last_item_index;; i++) {
if (i < 0) {
continue;
}
if (items[i].item == NULL) {
handler(file, line_no, CONF_RET_NOENT);
break;
}
if (strncmp(items[i].item, key, MAX_KEY_LEN) != 0) {
if (last_item_index >= 0) {
i = -1;
last_item_index = -1;
}
continue;
}
@@ -410,6 +457,7 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
/* call item function */
last_file = current_conf_file;
current_conf_file = file;
current_conf_lineno = line_no;
call_ret = items[i].item_func(items[i].item, items[i].data, argc, argv);
ret = handler(file, line_no, call_ret);
if (ret != 0) {
@@ -422,6 +470,7 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
current_conf_file = last_file;
}
last_item_index = i;
break;
}
}

View File

@@ -459,14 +459,21 @@ static int _smartdns_init(void)
int ret = 0;
const char *logfile = _smartdns_log_path();
int i = 0;
char logdir[PATH_MAX] = {0};
int logbuffersize = 0;
ret = tlog_init(logfile, dns_conf_log_size, dns_conf_log_num, 0, 0);
if (get_system_mem_size() > 1024 * 1024 * 1024) {
logbuffersize = 1024 * 1024;
}
ret = tlog_init(logfile, dns_conf_log_size, dns_conf_log_num, logbuffersize, TLOG_NONBLOCK);
if (ret != 0) {
tlog(TLOG_ERROR, "start tlog failed.\n");
goto errout;
}
if (verbose_screen != 0 || dns_conf_log_console != 0) {
safe_strncpy(logdir, _smartdns_log_path(), PATH_MAX);
if (verbose_screen != 0 || dns_conf_log_console != 0 || access(dir_name(logdir), W_OK) != 0) {
tlog_setlogscreen(1);
}
@@ -736,9 +743,11 @@ static void smartdns_test_notify_func(int fd_notify, uint64_t retval)
}
}
#define smartdns_close_allfds() close_all_fd(fd_notify);
int smartdns_main(int argc, char *argv[], int fd_notify)
#else
#define smartdns_test_notify(retval)
#define smartdns_close_allfds() close_all_fd(-1);
int main(int argc, char *argv[])
#endif
{
@@ -750,6 +759,7 @@ int main(int argc, char *argv[])
int signal_ignore = 0;
sigset_t empty_sigblock;
struct stat sb;
int daemon_ret = 0;
safe_strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN);
@@ -762,6 +772,7 @@ int main(int argc, char *argv[])
/* patch for Asus router: unblock all signal*/
sigemptyset(&empty_sigblock);
sigprocmask(SIG_SETMASK, &empty_sigblock, NULL);
smartdns_close_allfds();
while ((opt = getopt(argc, argv, "fhc:p:SvxN:")) != -1) {
switch (opt) {
@@ -769,10 +780,14 @@ int main(int argc, char *argv[])
is_foreground = 1;
break;
case 'c':
if (full_path(config_file, sizeof(config_file), optarg) != 0) {
snprintf(config_file, sizeof(config_file), "%s", optarg);
}
break;
case 'p':
if (strncmp(optarg, "-", 2) == 0 || full_path(pid_file, sizeof(pid_file), optarg) != 0) {
snprintf(pid_file, sizeof(pid_file), "%s", optarg);
}
break;
case 'S':
signal_ignore = 1;
@@ -794,23 +809,35 @@ int main(int argc, char *argv[])
}
}
if (dns_server_load_conf(config_file) != 0) {
ret = dns_server_load_conf(config_file);
if (ret != 0) {
fprintf(stderr, "load config failed.\n");
goto errout;
}
if (is_foreground == 0) {
if (daemon(0, 0) < 0) {
fprintf(stderr, "run daemon process failed, %s\n", strerror(errno));
if (is_foreground == 0 && dns_no_daemon == 0) {
daemon_ret = run_daemon();
if (daemon_ret < 0) {
char buff[4096];
char *log_path = realpath(_smartdns_log_path(), buff);
if (log_path != NULL && access(log_path, F_OK) == 0 && daemon_ret != -2) {
fprintf(stderr, "run daemon failed, please check log at %s\n", log_path);
}
return 1;
}
if (daemon_ret == 0) {
return 0;
}
}
if (signal_ignore == 0) {
_reg_signal();
}
if (strncmp(pid_file, "-", 2) != 0 && create_pid_file(pid_file) != 0) {
if (strncmp(pid_file, "-", 2) != 0 && dns_no_pidfile == 0 && create_pid_file(pid_file) != 0) {
ret = -2;
goto errout;
}
@@ -818,9 +845,10 @@ int main(int argc, char *argv[])
signal(SIGINT, _sig_exit);
signal(SIGTERM, _sig_exit);
if (_smartdns_init_pre() != 0) {
ret = _smartdns_init_pre();
if (ret != 0) {
fprintf(stderr, "init failed.\n");
return 1;
goto errout;
}
drop_root_privilege();
@@ -831,11 +859,21 @@ int main(int argc, char *argv[])
goto errout;
}
if (daemon_ret > 0) {
ret = daemon_kickoff(daemon_ret, 0, dns_conf_log_console | verbose_screen);
if (ret != 0) {
goto errout;
}
}
smartdns_test_notify(1);
ret = _smartdns_run();
_smartdns_exit();
return ret;
errout:
if (daemon_ret > 0) {
daemon_kickoff(daemon_ret, ret, dns_conf_log_console | verbose_screen);
}
smartdns_test_notify(2);
return 1;
}

View File

@@ -187,7 +187,7 @@ static int _tlog_mkdir(const char *path)
return 0;
}
while (*path == ' ' && *path != '\0') {
while (*path == ' ') {
path++;
}
@@ -330,7 +330,7 @@ void tlog_logcount(struct tlog_log *log, int count)
log->logcount = count;
}
void tlog_set_permission(struct tlog_log *log, unsigned int file, unsigned int archive)
void tlog_set_permission(struct tlog_log *log, mode_t file, mode_t archive)
{
log->file_perm = file;
log->archive_perm = archive;
@@ -748,7 +748,7 @@ static int _tlog_list_dir(const char *path, list_callback callback, void *userpt
dir = opendir(path);
if (dir == NULL) {
fprintf(stderr, "open directory failed, %s\n", strerror(errno));
fprintf(stderr, "tlog: open directory failed, %s\n", strerror(errno));
goto errout;
}
@@ -859,7 +859,7 @@ static int _tlog_remove_oldlog(struct tlog_log *log)
/* get total log file number */
if (_tlog_list_dir(log->logdir, _tlog_count_log_callback, &count_log) != 0) {
fprintf(stderr, "get log file count failed.\n");
fprintf(stderr, "tlog: get log file count failed.\n");
return -1;
}
@@ -896,7 +896,7 @@ static int _tlog_log_lock(struct tlog_log *log)
snprintf(lock_file, sizeof(lock_file), "%s/%s.lock", log->logdir, log->logname);
fd = open(lock_file, O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
if (fd == -1) {
fprintf(stderr, "create pid file failed, %s", strerror(errno));
fprintf(stderr, "tlog: create lock file failed, %s", strerror(errno));
return -1;
}
@@ -1061,8 +1061,14 @@ static int _tlog_archive_log_compressed(struct tlog_log *log)
if (pid == 0) {
_tlog_close_all_fd();
execl(tlog.gzip_cmd, tlog.gzip_cmd, "-1", pending_file, NULL);
fprintf(stderr, "tlog: execl gzip failed, no compress\n");
log->nocompress = 1;
_exit(1);
} else if (pid < 0) {
if (errno == EPERM || errno == EACCES) {
fprintf(stderr, "tlog: vfork failed, errno: %d, no compress\n", errno);
log->nocompress = 1;
}
goto errout;
}
log->zip_pid = pid;
@@ -1195,9 +1201,9 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
return -1;
}
log->print_errmsg = 0;
fprintf(stderr, "create log dir %s failed, %s\n", log->logdir, strerror(errno));
fprintf(stderr, "tlog: create log dir %s failed, %s\n", log->logdir, strerror(errno));
if (errno == EACCES && log->logscreen == 0) {
fprintf(stderr, "no permission to write log file, output log to console\n");
fprintf(stderr, "tlog: no permission to write log file, output log to console\n");
tlog_logscreen(log, 1);
tlog_logcount(log, 0);
}
@@ -1211,7 +1217,7 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
return -1;
}
fprintf(stderr, "open log file %s failed, %s\n", logfile, strerror(errno));
fprintf(stderr, "tlog: open log file %s failed, %s\n", logfile, strerror(errno));
log->print_errmsg = 0;
return -1;
}
@@ -1752,13 +1758,13 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
struct tlog_log *log = NULL;
if (tlog.run == 0) {
fprintf(stderr, "tlog is not initialized.");
fprintf(stderr, "tlog: tlog is not initialized.\n");
return NULL;
}
log = (struct tlog_log *)malloc(sizeof(*log));
if (log == NULL) {
fprintf(stderr, "malloc log failed.");
fprintf(stderr, "tlog: malloc log failed.\n");
return NULL;
}
@@ -1800,7 +1806,7 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
log->buff = (char *)malloc(log->buffsize);
if (log->buff == NULL) {
fprintf(stderr, "malloc log buffer failed, %s\n", strerror(errno));
fprintf(stderr, "tlog: malloc log buffer failed, %s\n", strerror(errno));
goto errout;
}
@@ -1888,7 +1894,7 @@ static void tlog_fork_child(void)
pthread_attr_init(&attr);
int ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
if (ret != 0) {
fprintf(stderr, "create tlog work thread failed, %s\n", strerror(errno));
fprintf(stderr, "tlog: create tlog work thread failed, %s\n", strerror(errno));
goto errout;
}
@@ -1910,12 +1916,12 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
struct tlog_log *log = NULL;
if (tlog_format != NULL) {
fprintf(stderr, "tlog already initialized.\n");
fprintf(stderr, "tlog: already initialized.\n");
return -1;
}
if (buffsize > 0 && buffsize < TLOG_MAX_LINE_SIZE_SET * 2) {
fprintf(stderr, "buffer size is invalid.\n");
fprintf(stderr, "tlog: buffer size is invalid.\n");
return -1;
}
@@ -1932,19 +1938,19 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
log = tlog_open(logfile, maxlogsize, maxlogcount, buffsize, flag);
if (log == NULL) {
fprintf(stderr, "init tlog root failed.\n");
fprintf(stderr, "tlog: init tlog root failed.\n");
goto errout;
}
tlog_reg_output_func(log, _tlog_root_write_log);
if ((flag & TLOG_NOCOMPRESS) == 0 && tlog.gzip_cmd[0] == '\0') {
fprintf(stderr, "can not find gzip command, disable compress.\n");
fprintf(stderr, "tlog: can not find gzip command, disable compress.\n");
}
tlog.root = log;
ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
if (ret != 0) {
fprintf(stderr, "create tlog work thread failed, %s\n", strerror(errno));
fprintf(stderr, "tlog: create tlog work thread failed, %s\n", strerror(errno));
goto errout;
}

View File

@@ -1,6 +1,6 @@
/*
* tinylog
* Copyright (C) 2018-2021 Ruilin Peng (Nick) <pymumu@gmail.com>
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>
* https://github.com/pymumu/tinylog
*/
@@ -139,7 +139,7 @@ steps:
read _tlog_format for example.
*/
typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_loginfo *info, void *userptr, const char *format, va_list ap);
extern int tlog_reg_format_func(tlog_format_func func);
extern int tlog_reg_format_func(tlog_format_func callback);
/* register log output callback
Note: info is invalid when flag TLOG_SEGMENT is not set.

View File

@@ -25,6 +25,7 @@
#include "util.h"
#include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
@@ -38,11 +39,13 @@
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/sysinfo.h>
@@ -806,7 +809,11 @@ int create_pid_file(const char *pid_file)
}
if (lockf(fd, F_TLOCK, 0) < 0) {
fprintf(stderr, "Server is already running.\n");
memset(buff, 0, TMP_BUFF_LEN_32);
if (read(fd, buff, TMP_BUFF_LEN_32) <= 0) {
buff[0] = '\0';
}
fprintf(stderr, "Server is already running, pid is %s", buff);
goto errout;
}
@@ -831,6 +838,27 @@ errout:
return -1;
}
int full_path(char *normalized_path, int normalized_path_len, const char *path)
{
const char *p = path;
if (path == NULL || normalized_path == NULL) {
return -1;
}
while (*p == ' ') {
p++;
}
if (*p == '\0' || *p == '/') {
return -1;
}
char buf[PATH_MAX];
snprintf(normalized_path, normalized_path_len, "%s/%s", getcwd(buf, sizeof(buf)), path);
return 0;
}
int generate_cert_key(const char *key_path, const char *cert_path, const char *san, int days)
{
int ret = -1;
@@ -1479,6 +1507,158 @@ out:
return ret;
}
static void _close_all_fd_by_res(void)
{
struct rlimit lim;
int maxfd = 0;
int i = 0;
getrlimit(RLIMIT_NOFILE, &lim);
maxfd = lim.rlim_cur;
if (maxfd > 4096) {
maxfd = 4096;
}
for (i = 3; i < maxfd; i++) {
close(i);
}
}
void close_all_fd(int keepfd)
{
DIR *dirp;
int dir_fd = -1;
struct dirent *dentp;
dirp = opendir("/proc/self/fd");
if (dirp == NULL) {
goto errout;
}
dir_fd = dirfd(dirp);
while ((dentp = readdir(dirp)) != NULL) {
int fd = atol(dentp->d_name);
if (fd < 0) {
continue;
}
if (fd == dir_fd || fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == keepfd) {
continue;
}
close(fd);
}
closedir(dirp);
return;
errout:
if (dirp) {
closedir(dirp);
}
_close_all_fd_by_res();
return;
}
int daemon_kickoff(int fd, int status, int no_close)
{
if (fd <= 0) {
return -1;
}
int ret = write(fd, &status, sizeof(status));
if (ret != sizeof(status)) {
return -1;
}
if (no_close == 0) {
int fd_null = open("/dev/null", O_RDWR);
if (fd_null < 0) {
fprintf(stderr, "open /dev/null failed, %s\n", strerror(errno));
return -1;
}
dup2(fd_null, STDIN_FILENO);
dup2(fd_null, STDOUT_FILENO);
dup2(fd_null, STDERR_FILENO);
if (fd_null > 2) {
close(fd_null);
}
}
close(fd);
return 0;
}
int run_daemon()
{
pid_t pid = 0;
int fds[2] = {0};
if (pipe(fds) != 0) {
fprintf(stderr, "run daemon process failed, pipe failed, %s\n", strerror(errno));
return -1;
}
pid = fork();
if (pid < 0) {
fprintf(stderr, "run daemon process failed, fork failed, %s\n", strerror(errno));
close(fds[0]);
close(fds[1]);
return -1;
} else if (pid > 0) {
struct pollfd pfd;
int ret = 0;
int status = 0;
close(fds[1]);
pfd.fd = fds[0];
pfd.events = POLLIN;
pfd.revents = 0;
ret = poll(&pfd, 1, 1000);
if (ret <= 0) {
fprintf(stderr, "run daemon process failed, wait child timeout\n");
goto errout;
}
if (!(pfd.revents & POLLIN)) {
goto errout;
}
ret = read(fds[0], &status, sizeof(status));
if (ret != sizeof(status)) {
goto errout;
}
return status;
}
setsid();
pid = fork();
if (pid < 0) {
fprintf(stderr, "double fork failed, %s\n", strerror(errno));
_exit(1);
} else if (pid > 0) {
_exit(0);
}
umask(0);
if (chdir("/") != 0) {
goto errout;
}
close(fds[0]);
return fds[1];
errout:
kill(pid, SIGKILL);
return -1;
}
#ifdef DEBUG
struct _dns_read_packet_info {
int data_len;

View File

@@ -105,6 +105,8 @@ int generate_cert_key(const char *key_path, const char *cert_path, const char *s
int create_pid_file(const char *pid_file);
int full_path(char *normalized_path, int normalized_path_len, const char *path);
/* Parse a TLS packet for the Server Name Indication extension in the client
* hello handshake, returning the first server name found (pointer to static
* array)
@@ -138,6 +140,12 @@ uint64_t get_free_space(const char *path);
void print_stack(void);
void close_all_fd(int keepfd);
int run_daemon(void);
int daemon_kickoff(int fd, int status, int no_close);
int write_file(const char *filename, void *data, int data_len);
int dns_packet_save(const char *dir, const char *type, const char *from, const void *packet, int packet_len);

View File

@@ -161,3 +161,94 @@ cache-persist no)""");
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::1010:1010");
}
TEST_F(Address, multiaddress)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
if (request->qtype == DNS_T_A) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
return smartdns::SERVER_REQUEST_OK;
} else if (request->qtype == DNS_T_AAAA) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
return smartdns::SERVER_REQUEST_OK;
}
return smartdns::SERVER_REQUEST_SOA;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053
log-num 0
log-console yes
log-level debug
speed-check-mode none
address /a.com/10.10.10.10,11.11.11.11,22.22.22.22
address /a.com/64:ff9b::1010:1010,64:ff9b::1111:1111,64:ff9b::2222:2222
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("a.com A", 60053));
std::cout << client.GetResult() << std::endl;
std::map<std::string, smartdns::DNSRecord *> result;
ASSERT_EQ(client.GetAnswerNum(), 3);
EXPECT_EQ(client.GetStatus(), "NOERROR");
auto answers = client.GetAnswer();
for (int i = 0; i < client.GetAnswerNum(); i++) {
result[client.GetAnswer()[i].GetData()] = &answers[i];
}
ASSERT_NE(result.find("10.10.10.10"), result.end());
auto check_result = result["10.10.10.10"];
EXPECT_EQ(check_result->GetName(), "a.com");
EXPECT_EQ(check_result->GetTTL(), 600);
EXPECT_EQ(check_result->GetType(), "A");
EXPECT_EQ(check_result->GetData(), "10.10.10.10");
ASSERT_NE(result.find("11.11.11.11"), result.end());
check_result = result["11.11.11.11"];
EXPECT_EQ(check_result->GetName(), "a.com");
EXPECT_EQ(check_result->GetTTL(), 600);
EXPECT_EQ(check_result->GetType(), "A");
EXPECT_EQ(check_result->GetData(), "11.11.11.11");
ASSERT_NE(result.find("22.22.22.22"), result.end());
check_result = result["22.22.22.22"];
EXPECT_EQ(check_result->GetName(), "a.com");
EXPECT_EQ(check_result->GetTTL(), 600);
EXPECT_EQ(check_result->GetType(), "A");
EXPECT_EQ(check_result->GetData(), "22.22.22.22");
result.clear();
ASSERT_TRUE(client.Query("a.com AAAA", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 3);
EXPECT_EQ(client.GetStatus(), "NOERROR");
answers = client.GetAnswer();
for (int i = 0; i < client.GetAnswerNum(); i++) {
result[client.GetAnswer()[i].GetData()] = &answers[i];
}
ASSERT_NE(result.find("64:ff9b::1010:1010"), result.end());
check_result = result["64:ff9b::1010:1010"];
EXPECT_EQ(check_result->GetName(), "a.com");
EXPECT_EQ(check_result->GetTTL(), 600);
EXPECT_EQ(check_result->GetType(), "AAAA");
EXPECT_EQ(check_result->GetData(), "64:ff9b::1010:1010");
ASSERT_NE(result.find("64:ff9b::1111:1111"), result.end());
check_result = result["64:ff9b::1111:1111"];
EXPECT_EQ(check_result->GetName(), "a.com");
EXPECT_EQ(check_result->GetTTL(), 600);
EXPECT_EQ(check_result->GetType(), "AAAA");
EXPECT_EQ(check_result->GetData(), "64:ff9b::1111:1111");
ASSERT_NE(result.find("64:ff9b::2222:2222"), result.end());
check_result = result["64:ff9b::2222:2222"];
EXPECT_EQ(check_result->GetName(), "a.com");
EXPECT_EQ(check_result->GetTTL(), 600);
EXPECT_EQ(check_result->GetType(), "AAAA");
EXPECT_EQ(check_result->GetData(), "64:ff9b::2222:2222");
}

View File

@@ -127,6 +127,16 @@ cache-persist no)""");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 5);
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
sleep(1);
ASSERT_TRUE(client.Query("a.com", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 5);
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
}
TEST_F(Cache, max_reply_ttl_expired)

View File

@@ -77,7 +77,6 @@ TEST_F(Cname, subdomain1)
if (request->domain == "s.a.com") {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700);
return smartdns::SERVER_REQUEST_OK;
}
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
@@ -114,7 +113,6 @@ TEST_F(Cname, subdomain2)
if (request->domain == "a.s.a.com") {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700);
return smartdns::SERVER_REQUEST_OK;
}
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
@@ -139,7 +137,6 @@ cache-persist no)""");
EXPECT_EQ(client.GetAnswer()[1].GetData(), "4.5.6.7");
}
TEST_F(Cname, loop)
{
smartdns::MockServer server_upstream;
@@ -153,7 +150,6 @@ TEST_F(Cname, loop)
if (request->domain == "s.a.com") {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700);
return smartdns::SERVER_REQUEST_OK;
}
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);

124
test/cases/test-ddns.cc Normal file
View File

@@ -0,0 +1,124 @@
/*************************************************************************
*
* 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/>.
*/
#include "client.h"
#include "dns.h"
#include "include/utils.h"
#include "server.h"
#include "util.h"
#include "gtest/gtest.h"
#include <fstream>
class DDNS : public ::testing::Test
{
protected:
virtual void SetUp() {}
virtual void TearDown() {}
};
TEST_F(DDNS, smartdns)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
return smartdns::SERVER_REQUEST_SOA;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053
log-num 0
log-console yes
dualstack-ip-selection no
log-level debug
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("smartdns A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "smartdns");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "127.0.0.1");
ASSERT_TRUE(client.Query("smartdns AAAA", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "smartdns");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "::1");
}
TEST_F(DDNS, ddns)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
return smartdns::SERVER_REQUEST_SOA;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053
log-num 0
ddns-domain test.ddns.com
ddns-domain test.ddns.org
log-console yes
dualstack-ip-selection no
log-level debug
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("test.ddns.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "test.ddns.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "127.0.0.1");
ASSERT_TRUE(client.Query("test.ddns.com AAAA", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "test.ddns.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "::1");
ASSERT_TRUE(client.Query("test.ddns.org A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "test.ddns.org");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "127.0.0.1");
ASSERT_TRUE(client.Query("test.ddns.org AAAA", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "test.ddns.org");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "::1");
}

262
test/cases/test-rule.cc Normal file
View File

@@ -0,0 +1,262 @@
/*************************************************************************
*
* 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/>.
*/
#include "client.h"
#include "dns.h"
#include "include/utils.h"
#include "server.h"
#include "util.h"
#include "gtest/gtest.h"
#include <fstream>
class Rule : public ::testing::Test
{
protected:
virtual void SetUp() {}
virtual void TearDown() {}
};
TEST_F(Rule, Match)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
if (request->qtype == DNS_T_A) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
return smartdns::SERVER_REQUEST_OK;
} else if (request->qtype == DNS_T_AAAA) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
return smartdns::SERVER_REQUEST_OK;
}
return smartdns::SERVER_REQUEST_SOA;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053
log-num 0
log-console yes
log-level debug
speed-check-mode none
address /a.com/5.6.7.8
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
ASSERT_TRUE(client.Query("a.a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
ASSERT_TRUE(client.Query("aa.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "aa.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
}
TEST_F(Rule, PrefixWildcardMatch)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
if (request->qtype == DNS_T_A) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
return smartdns::SERVER_REQUEST_OK;
} else if (request->qtype == DNS_T_AAAA) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
return smartdns::SERVER_REQUEST_OK;
}
return smartdns::SERVER_REQUEST_SOA;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053
log-num 0
log-console yes
log-level debug
speed-check-mode none
address /*a.com/5.6.7.8
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
ASSERT_TRUE(client.Query("a.a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
ASSERT_TRUE(client.Query("aa.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "aa.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
ASSERT_TRUE(client.Query("ab.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "ab.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
}
TEST_F(Rule, SubDomainMatchOnly)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
if (request->qtype == DNS_T_A) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
return smartdns::SERVER_REQUEST_OK;
} else if (request->qtype == DNS_T_AAAA) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
return smartdns::SERVER_REQUEST_OK;
}
return smartdns::SERVER_REQUEST_SOA;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053
log-num 0
log-console yes
log-level debug
speed-check-mode none
address /*.a.com/5.6.7.8
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
ASSERT_TRUE(client.Query("a.a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
ASSERT_TRUE(client.Query("aa.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "aa.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
}
TEST_F(Rule, RootDomainMatchOnly)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
if (request->qtype == DNS_T_A) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
return smartdns::SERVER_REQUEST_OK;
} else if (request->qtype == DNS_T_AAAA) {
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
return smartdns::SERVER_REQUEST_OK;
}
return smartdns::SERVER_REQUEST_SOA;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053
log-num 0
log-console yes
log-level debug
speed-check-mode none
address /-.a.com/5.6.7.8
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
ASSERT_TRUE(client.Query("a.a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
ASSERT_TRUE(client.Query("b.a.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
ASSERT_TRUE(client.Query("ba.com A", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "ba.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
}

View File

@@ -220,7 +220,6 @@ cache-persist no)""");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
}
TEST_F(SpeedCheck, tcp_faster_than_ping)
{
smartdns::MockServer server_upstream;

View File

@@ -245,6 +245,148 @@ cache-persist no)""");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "2001:db8::1");
}
TEST_F(SubNet, v4_server_subnet_txt)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
if (request->qtype != DNS_T_TXT) {
return smartdns::SERVER_REQUEST_SOA;
}
struct dns_opt_ecs ecs;
struct dns_rrs *rrs = NULL;
int rr_count = 0;
int i = 0;
int ret = 0;
int has_ecs = 0;
rr_count = 0;
rrs = dns_get_rrs_start(request->packet, DNS_RRS_OPT, &rr_count);
if (rr_count <= 0) {
return smartdns::SERVER_REQUEST_ERROR;
}
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
memset(&ecs, 0, sizeof(ecs));
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
if (ret != 0) {
continue;
}
has_ecs = 1;
break;
}
if (has_ecs == 0) {
return smartdns::SERVER_REQUEST_ERROR;
}
if (ecs.family != DNS_OPT_ECS_FAMILY_IPV4) {
return smartdns::SERVER_REQUEST_ERROR;
}
if (memcmp(ecs.addr, "\x08\x08\x08\x00", 4) != 0) {
return smartdns::SERVER_REQUEST_ERROR;
}
if (ecs.source_prefix != 24) {
return smartdns::SERVER_REQUEST_ERROR;
}
dns_add_TXT(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 6, "hello world");
return smartdns::SERVER_REQUEST_OK;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053 -subnet 8.8.8.8/24
log-num 0
log-console yes
dualstack-ip-selection no
log-level debug
rr-ttl-min 0
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("a.com TXT", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 6);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "TXT");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "\"hello world\"");
}
TEST_F(SubNet, v6_default_subnet_txt)
{
smartdns::MockServer server_upstream;
smartdns::Server server;
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
if (request->qtype != DNS_T_TXT) {
return smartdns::SERVER_REQUEST_SOA;
}
struct dns_opt_ecs ecs;
struct dns_rrs *rrs = NULL;
int rr_count = 0;
int i = 0;
int ret = 0;
int has_ecs = 0;
rr_count = 0;
rrs = dns_get_rrs_start(request->packet, DNS_RRS_OPT, &rr_count);
if (rr_count <= 0) {
return smartdns::SERVER_REQUEST_ERROR;
}
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
memset(&ecs, 0, sizeof(ecs));
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
if (ret != 0) {
continue;
}
has_ecs = 1;
break;
}
if (has_ecs == 0) {
return smartdns::SERVER_REQUEST_ERROR;
}
if (ecs.family != DNS_OPT_ECS_FAMILY_IPV6) {
return smartdns::SERVER_REQUEST_ERROR;
}
if (memcmp(ecs.addr, "\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00", 16) != 0) {
return smartdns::SERVER_REQUEST_ERROR;
}
if (ecs.source_prefix != 64) {
return smartdns::SERVER_REQUEST_ERROR;
}
dns_add_TXT(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 6, "hello world");
return smartdns::SERVER_REQUEST_OK;
});
server.Start(R"""(bind [::]:60053
server 127.0.0.1:61053
log-num 0
log-console yes
dualstack-ip-selection no
rr-ttl-min 0
edns-client-subnet ffff:ffff:ffff:ffff:ffff::/64
log-level debug
cache-persist no)""");
smartdns::Client client;
ASSERT_TRUE(client.Query("a.com TXT", 60053));
std::cout << client.GetResult() << std::endl;
ASSERT_EQ(client.GetAnswerNum(), 1);
EXPECT_EQ(client.GetStatus(), "NOERROR");
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 6);
EXPECT_EQ(client.GetAnswer()[0].GetType(), "TXT");
EXPECT_EQ(client.GetAnswer()[0].GetData(), "\"hello world\"");
}
TEST_F(SubNet, per_server)
{
smartdns::MockServer server_upstream1;