Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ba6ee7cb9 | ||
|
|
601ebd590e | ||
|
|
b133ce408a | ||
|
|
8d3a62c568 | ||
|
|
93a8b87c17 | ||
|
|
ffc331af21 | ||
|
|
89e958abfa | ||
|
|
2576fdb02f | ||
|
|
7ff6ae3ea0 | ||
|
|
c2b072b523 | ||
|
|
1df9d624b4 | ||
|
|
6b021946aa | ||
|
|
087c9f5df2 | ||
|
|
e66928f27f | ||
|
|
8a9a11d6d9 | ||
|
|
a6e5ceb675 | ||
|
|
08567c458b | ||
|
|
234c721011 | ||
|
|
45346705d8 | ||
|
|
9b7b2ad12d | ||
|
|
f072ff3412 | ||
|
|
ad43c796cf | ||
|
|
f5c8d3ce57 | ||
|
|
f621b424e2 | ||
|
|
d59c148a28 | ||
|
|
8ea34ab176 | ||
|
|
0340d272c3 |
43
.clang-tidy
Normal file
43
.clang-tidy
Normal 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
|
||||
@@ -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:
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Add custom settings here.
|
||||
# please read https://pymumu.github.io/smartdns/config/basic-config/
|
||||
# please read https://pymumu.github.io/smartdns/config/basic-config/
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
21
src/dns.c
21
src/dns.c
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
208
src/dns_client.c
208
src/dns_client.c
@@ -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);
|
||||
_dns_client_check_udp_nat(query);
|
||||
|
||||
/* 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);
|
||||
|
||||
347
src/dns_conf.c
347
src/dns_conf.c
@@ -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);
|
||||
domain_key[len] = '.';
|
||||
len++;
|
||||
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,53 +1575,79 @@ 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) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV4_SOA;
|
||||
} else if (strncmp(domain_address, "#6", sizeof("#6")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV6_SOA;
|
||||
} else if (strncmp(domain_address, "#", sizeof("#")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_SOA;
|
||||
} else {
|
||||
goto errout;
|
||||
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;
|
||||
}
|
||||
|
||||
/* add SOA rule */
|
||||
if (_config_domain_rule_flag_set(domain, flag, 0) != 0) {
|
||||
goto errout;
|
||||
if (ptr) {
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if (*(domain_address) == '-') {
|
||||
if (strncmp(domain_address, "-4", sizeof("-4")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV4_IGN;
|
||||
} else if (strncmp(domain_address, "-6", sizeof("-6")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV6_IGN;
|
||||
} else if (strncmp(domain_address, "-", sizeof("-")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IGN;
|
||||
} else {
|
||||
goto errout;
|
||||
if (*(field) == '#') {
|
||||
if (strncmp(field, "#4", sizeof("#4")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV4_SOA;
|
||||
} else if (strncmp(field, "#6", sizeof("#6")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV6_SOA;
|
||||
} else if (strncmp(field, "#", sizeof("#")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_SOA;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* add SOA rule */
|
||||
if (_config_domain_rule_flag_set(domain, flag, 0) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if (*(field) == '-') {
|
||||
if (strncmp(field, "-4", sizeof("-4")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV4_IGN;
|
||||
} else if (strncmp(field, "-6", sizeof("-6")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV6_IGN;
|
||||
} else if (strncmp(field, "-", sizeof("-")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IGN;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* ignore rule */
|
||||
if (_config_domain_rule_flag_set(domain, flag, 0) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ignore rule */
|
||||
if (_config_domain_rule_flag_set(domain, flag, 0) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* add domain to ART-tree */
|
||||
if (_config_domain_rule_add(domain, type, address) != 0) {
|
||||
goto errout;
|
||||
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);
|
||||
}
|
||||
|
||||
_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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
287
src/dns_server.c
287
src/dns_server.c
@@ -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);
|
||||
} 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);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
_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,25 +4620,21 @@ 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);
|
||||
tlog(TLOG_DEBUG, "force qtype %d soa", request->qtype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
_dns_server_reply_SOA(DNS_RC_NOERROR, request);
|
||||
tlog(TLOG_DEBUG, "force qtype %d soa", request->qtype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _dns_server_process_speed_rule(struct dns_request *request)
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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';
|
||||
continue;
|
||||
read_len -= 1;
|
||||
current_line_wrap = 1;
|
||||
}
|
||||
line_len = 0;
|
||||
|
||||
filed_num = sscanf(line, "%63s %8192[^\r\n]s", key, value);
|
||||
/* comment in wrap line, skip */
|
||||
if (is_last_line_wrap && read_len > 0) {
|
||||
if (*(line + line_len) == '#') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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':
|
||||
snprintf(config_file, sizeof(config_file), "%s", optarg);
|
||||
if (full_path(config_file, sizeof(config_file), optarg) != 0) {
|
||||
snprintf(config_file, sizeof(config_file), "%s", optarg);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
snprintf(pid_file, sizeof(pid_file), "%s", optarg);
|
||||
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;
|
||||
}
|
||||
|
||||
40
src/tlog.c
40
src/tlog.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
184
src/util.c
184
src/util.c
@@ -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;
|
||||
@@ -1604,7 +1784,7 @@ static int _dns_debug_display(struct dns_packet *packet)
|
||||
int ret = 0;
|
||||
|
||||
ret = dns_get_HTTPS_svcparm_start(rrs, &p, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target,
|
||||
DNS_MAX_CNAME_LEN);
|
||||
DNS_MAX_CNAME_LEN);
|
||||
if (ret != 0) {
|
||||
printf("get HTTPS svcparm failed\n");
|
||||
break;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
124
test/cases/test-ddns.cc
Normal 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");
|
||||
}
|
||||
@@ -39,17 +39,17 @@ TEST_F(DomainRule, bogus_nxdomain)
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
if (request->domain == "a.com") {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "10.11.12.13", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
if (request->domain == "a.com") {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "10.11.12.13", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -blacklist-ip
|
||||
@@ -64,7 +64,7 @@ cache-persist no)""");
|
||||
ASSERT_EQ(client.GetAuthorityNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NXDOMAIN");
|
||||
|
||||
ASSERT_TRUE(client.Query("b.com", 60053));
|
||||
ASSERT_TRUE(client.Query("b.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
|
||||
@@ -53,8 +53,8 @@ TEST_F(IPRule, white_list)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -whitelist-ip
|
||||
@@ -97,8 +97,8 @@ TEST_F(IPRule, black_list)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 10);
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 10);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -blacklist-ip
|
||||
@@ -134,10 +134,10 @@ TEST_F(IPRule, ignore_ip)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 90);
|
||||
server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 40);
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 90);
|
||||
server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 40);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -blacklist-ip
|
||||
|
||||
@@ -42,11 +42,11 @@ TEST_F(Ptr, query)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_PTR) {
|
||||
dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname");
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
if (request->qtype == DNS_T_PTR) {
|
||||
dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname");
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
@@ -127,11 +127,11 @@ TEST_F(Ptr, smartdns)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_PTR) {
|
||||
dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname");
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
if (request->qtype == DNS_T_PTR) {
|
||||
dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname");
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
262
test/cases/test-rule.cc
Normal file
262
test/cases/test-rule.cc
Normal 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");
|
||||
}
|
||||
@@ -44,7 +44,7 @@ TEST_F(Server, all_unreach)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "2001::", 128, 10000);
|
||||
server.MockPing(PING_TYPE_ICMP, "2001::", 128, 10000);
|
||||
server.Start(R"""(bind [::]:60053
|
||||
bind-tcp [::]:60053
|
||||
server tls://255.255.255.255
|
||||
@@ -58,11 +58,11 @@ cache-persist no)""");
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
EXPECT_EQ(client.GetStatus(), "SERVFAIL");
|
||||
EXPECT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetAnswerNum(), 0);
|
||||
|
||||
/* server should not crash */
|
||||
ASSERT_TRUE(client.Query("a.com +tcp", 60053));
|
||||
/* server should not crash */
|
||||
ASSERT_TRUE(client.Query("a.com +tcp", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
EXPECT_EQ(client.GetStatus(), "SERVFAIL");
|
||||
EXPECT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetAnswerNum(), 0);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user