diff --git a/etc/smartdns/smartdns.conf b/etc/smartdns/smartdns.conf index b68d7ffeca..3c3d2b4c95 100644 --- a/etc/smartdns/smartdns.conf +++ b/etc/smartdns/smartdns.conf @@ -203,7 +203,7 @@ log-level info # certificate path # ca-path [path] -# ca-path /etc/ss/certs +# ca-path /etc/ssl/certs # remote udp dns server list # server [IP]:[PORT]|URL [-blacklist-ip] [-whitelist-ip] [-check-edns] [-group [group] ...] [-exclude-default-group] diff --git a/src/dns_conf.c b/src/dns_conf.c index fe5c87e1b7..9ff3e1afe2 100644 --- a/src/dns_conf.c +++ b/src/dns_conf.c @@ -61,9 +61,6 @@ static time_t dns_conf_dnsmasq_lease_file_time; struct dns_hosts_table dns_hosts_table; int dns_hosts_record_num; -/* DNS64 */ -struct dns_dns64 dns_conf_dns_dns64; - /* SRV-HOST */ struct dns_srv_record_table dns_conf_srv_record_table; @@ -2833,6 +2830,11 @@ static int _config_dns64(void *data, int argc, char *argv[]) subnet = argv[1]; + if (strncmp(subnet, "-", 2U) == 0) { + memset(&_config_current_rule_group()->dns_dns64, 0, sizeof(struct dns_dns64)); + return 0; + } + p = prefix_pton(subnet, -1, &prefix, &errmsg); if (p == NULL) { goto errout; @@ -2848,8 +2850,9 @@ static int _config_dns64(void *data, int argc, char *argv[]) goto errout; } - memcpy(&dns_conf_dns_dns64.prefix, &prefix.add.sin6.s6_addr, sizeof(dns_conf_dns_dns64.prefix)); - dns_conf_dns_dns64.prefix_len = prefix.bitlen; + struct dns_dns64 *dns64 = &(_config_current_rule_group()->dns_dns64); + memcpy(&dns64->prefix, &prefix.add.sin6.s6_addr, sizeof(dns64->prefix)); + dns64->prefix_len = prefix.bitlen; return 0; diff --git a/src/dns_conf.h b/src/dns_conf.h index fefb402541..99cd095ab3 100644 --- a/src/dns_conf.h +++ b/src/dns_conf.h @@ -448,17 +448,27 @@ struct dns_conf_ipset_nftset { struct dns_nftset_names nftset_no_speed; }; +struct dns_dns64 { + unsigned char prefix[DNS_RR_AAAA_LEN]; + uint32_t prefix_len; +}; + struct dns_conf_group { struct hlist_node node; struct dns_conf_domain_rule domain_rule; struct dns_conf_address_rule address_rule; uint8_t *soa_table; + /* === AUTO COPY FIELD BEGIN === */ char copy_data_section_begin[0]; struct dns_conf_ipset_nftset ipset_nftset; struct dns_domain_check_orders check_orders; /* ECS */ struct dns_edns_client_subnet ipv4_ecs; struct dns_edns_client_subnet ipv6_ecs; + + /* DNS64 */ + struct dns_dns64 dns_dns64; + int force_AAAA_SOA; int dualstack_ip_selection; int dns_dualstack_ip_allow_force_AAAA; @@ -477,6 +487,7 @@ struct dns_conf_group { int dns_max_reply_ip_num; enum response_mode_type dns_response_mode; char copy_data_section_end[0]; + /* === AUTO COPY FIELD END === */ const char *group_name; }; @@ -616,11 +627,6 @@ struct dns_set_rule_flags_callback_args { int is_clear_flag; }; -struct dns_dns64 { - unsigned char prefix[DNS_RR_AAAA_LEN]; - uint32_t prefix_len; -}; - struct dns_srv_record { struct list_head list; char host[DNS_MAX_CNAME_LEN]; @@ -640,8 +646,6 @@ struct dns_srv_record_table { }; extern struct dns_srv_record_table dns_conf_srv_record_table; -extern struct dns_dns64 dns_conf_dns_dns64; - extern struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP]; extern int dns_conf_bind_ip_num; diff --git a/src/dns_server.c b/src/dns_server.c index 3c5464d905..938a9f028a 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -625,7 +625,7 @@ static int _dns_server_is_dns64_request(struct dns_request *request) return 0; } - if (dns_conf_dns_dns64.prefix_len <= 0) { + if (request->conf->dns_dns64.prefix_len <= 0) { return 0; } @@ -4138,6 +4138,9 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d case DNS_T_SOA: { /* if DNS64 enabled, skip check SOA. */ if (_dns_server_is_dns64_request(request)) { + if (request->has_ip) { + _dns_server_request_complete(request); + } break; } @@ -4513,7 +4516,7 @@ static void _dns_server_query_end(struct dns_request *request) if (request->dualstack_selection_query == 1) { if ((conf->ipset_nftset.ipset_no_speed.ipv4_enable || conf->ipset_nftset.nftset_no_speed.ip_enable || conf->ipset_nftset.ipset_no_speed.ipv6_enable || conf->ipset_nftset.nftset_no_speed.ip6_enable) && - dns_conf_dns_dns64.prefix_len == 0) { + request->conf->dns_dns64.prefix_len == 0) { /* if speed check fail enabled, we need reply quickly, otherwise wait for ping result.*/ _dns_server_request_complete(request); } @@ -5961,7 +5964,7 @@ _dns_server_process_dns64_callback(struct dns_request *request, struct dns_reque int addr_len = 0; if (request->has_ip == 1) { - if (memcmp(request->ip_addr, dns_conf_dns_dns64.prefix, 12) != 0) { + if (memcmp(request->ip_addr, request->conf->dns_dns64.prefix, 12) != 0) { return DNS_CHILD_POST_SKIP; } } @@ -5976,11 +5979,12 @@ _dns_server_process_dns64_callback(struct dns_request *request, struct dns_reque request->ttl_cname = child_request->ttl_cname; } - if (child_request->has_ip == 0) { + if (child_request->has_ip == 0 && request->has_ip == 0) { + request->rcode = child_request->rcode; if (child_request->has_soa) { memcpy(&request->soa, &child_request->soa, sizeof(struct dns_soa)); request->has_soa = 1; - return DNS_CHILD_POST_SUCCESS; + return DNS_CHILD_POST_SKIP; } if (request->has_soa == 0) { @@ -5990,13 +5994,15 @@ _dns_server_process_dns64_callback(struct dns_request *request, struct dns_reque return DNS_CHILD_POST_FAIL; } - memcpy(request->ip_addr, dns_conf_dns_dns64.prefix, 16); - memcpy(request->ip_addr + 12, child_request->ip_addr, 4); - request->ip_ttl = child_request->ip_ttl; - request->has_ip = 1; - request->has_soa = 0; + if (request->has_ip == 0 && child_request->has_ip == 1) { + request->rcode = child_request->rcode; + memcpy(request->ip_addr, request->conf->dns_dns64.prefix, 12); + memcpy(request->ip_addr + 12, child_request->ip_addr, 4); + request->ip_ttl = child_request->ip_ttl; + request->has_ip = 1; + request->has_soa = 0; + } - request->rcode = child_request->rcode; pthread_mutex_lock(&request->ip_map_lock); hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node) { @@ -6026,7 +6032,7 @@ _dns_server_process_dns64_callback(struct dns_request *request, struct dns_reque new_addr_map->addr_type = DNS_T_AAAA; addr_len = DNS_RR_AAAA_LEN; - memcpy(new_addr_map->ip_addr, dns_conf_dns_dns64.prefix, 16); + memcpy(new_addr_map->ip_addr, request->conf->dns_dns64.prefix, 16); memcpy(new_addr_map->ip_addr + 12, addr_map->ip_addr, 4); new_addr_map->ping_time = addr_map->ping_time; @@ -6042,7 +6048,7 @@ _dns_server_process_dns64_callback(struct dns_request *request, struct dns_reque return DNS_CHILD_POST_NO_RESPONSE; } - return DNS_CHILD_POST_SUCCESS; + return DNS_CHILD_POST_SKIP; } static int _dns_server_process_dns64(struct dns_request *request) @@ -6060,6 +6066,8 @@ static int _dns_server_process_dns64(struct dns_request *request) return -1; } + request->dualstack_selection = 0; + child_request->prefetch_flags |= PREFETCH_FLAGS_NO_DUALSTACK; request->request_wait++; int ret = _dns_server_do_query(child_request, 0); if (ret != 0) { @@ -6069,7 +6077,7 @@ static int _dns_server_process_dns64(struct dns_request *request) } _dns_server_request_release_complete(child_request, 0); - return 1; + return 0; errout: @@ -6288,6 +6296,10 @@ static int _dns_server_process_cache(struct dns_request *request) goto reply_cache; } + if (_dns_server_is_dns64_request(request) == 1) { + goto reply_cache; + } + cache_key.qtype = dualstack_qtype; dualstack_dns_cache = dns_cache_lookup(&cache_key); if (dualstack_dns_cache == NULL && request->cname[0] != '\0') { diff --git a/test/cases/test-dns64.cc b/test/cases/test-dns64.cc index a9fab169e7..4a3810d043 100644 --- a/test/cases/test-dns64.cc +++ b/test/cases/test-dns64.cc @@ -59,3 +59,85 @@ dualstack-ip-selection no EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA"); EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::102:304"); } + +TEST_F(DNS64, with_dualstack) +{ + 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"); + return smartdns::SERVER_REQUEST_OK; + } + return smartdns::SERVER_REQUEST_SOA; + }); + + server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 200); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +dns64 64:ff9b::/96 +)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.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(), "a.com"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::102:304"); + EXPECT_LT(client.GetQueryTime(), 100); + + usleep(500000); + ASSERT_TRUE(client.Query("a.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(), "a.com"); + EXPECT_GT(client.GetAnswer()[0].GetTTL(), 500); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::102:304"); + EXPECT_LT(client.GetQueryTime(), 100); +} + + +TEST_F(DNS64, with_AAAA_result) +{ + 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"); + return smartdns::SERVER_REQUEST_OK; + } + + if (request->qtype == DNS_T_AAAA) { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "2001:db8::1"); + smartdns::MockServer::AddIP(request, request->domain.c_str(), "2001:db8::2"); + return smartdns::SERVER_REQUEST_OK; + } + return smartdns::SERVER_REQUEST_SOA; + }); + + server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 300); + server.MockPing(PING_TYPE_ICMP, "2001:db8::1", 60, 90); + server.MockPing(PING_TYPE_ICMP, "2001:db8::2", 60, 100); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +dns64 64:ff9b::/96 +)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.com AAAA", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_LT(client.GetQueryTime(), 1200); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "2001:db8::1"); +} +