Skip to content

Commit

Permalink
dns_server: fix DNS64 issue and add group config support for DNS64
Browse files Browse the repository at this point in the history
  • Loading branch information
pymumu committed Apr 18, 2024
1 parent 2234976 commit 484251c
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 27 deletions.
2 changes: 1 addition & 1 deletion etc/smartdns/smartdns.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
13 changes: 8 additions & 5 deletions src/dns_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down
18 changes: 11 additions & 7 deletions src/dns_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
};

Expand Down Expand Up @@ -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];
Expand All @@ -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;

Expand Down
40 changes: 26 additions & 14 deletions src/dns_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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) {
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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) {
Expand All @@ -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:

Expand Down Expand Up @@ -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') {
Expand Down
82 changes: 82 additions & 0 deletions test/cases/test-dns64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

0 comments on commit 484251c

Please sign in to comment.