From 8c423fece07a83b92ced1995129dfec5f0486473 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Mon, 8 Jan 2024 22:20:15 +0800 Subject: [PATCH] dns_conf: bind speed-check-mode, force-qtype-soa with group. --- src/dns_conf.c | 69 +++++++++++------ src/dns_conf.h | 9 ++- src/dns_server.c | 10 +-- test/cases/test-group.cc | 160 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+), 33 deletions(-) diff --git a/src/dns_conf.c b/src/dns_conf.c index 7a2dda4b60..1e9f0624a9 100644 --- a/src/dns_conf.c +++ b/src/dns_conf.c @@ -45,8 +45,6 @@ struct dns_nftset_table { }; static struct dns_nftset_table dns_nftset_table; -uint8_t *dns_qtype_soa_table; - struct dns_domain_set_name_table dns_domain_set_name_table; struct dns_ip_set_name_table dns_ip_set_name_table; @@ -158,7 +156,6 @@ struct dns_conf_rule dns_conf_rule; struct dns_conf_client_rule dns_conf_client_rule; /* dual-stack selection */ -int dns_conf_dualstack_ip_selection = 1; int dns_conf_dualstack_ip_allow_force_AAAA; int dns_conf_dualstack_ip_selection_threshold = 10; @@ -170,7 +167,6 @@ int dns_conf_rr_ttl_reply_max; int dns_conf_rr_ttl_min = 600; int dns_conf_rr_ttl_max; int dns_conf_local_ttl; -int dns_conf_force_AAAA_SOA; int dns_conf_force_no_cname; int dns_conf_nftset_debug_enable; int dns_conf_mdns_lookup; @@ -494,16 +490,33 @@ static void _config_current_group_pop(void) dns_conf_current_group_info = group_info; } -static void _config_rule_group_setup_value(struct dns_conf_group_info *group_info) +static int _config_rule_group_setup_value(struct dns_conf_group_info *group_info) { struct dns_conf_group *group_rule = group_info->rule; + int soa_talbe_size = MAX_QTYPE_NUM / 8 + 1; + uint8_t *soa_table = NULL; + + soa_table = malloc(soa_talbe_size); + if (soa_table == NULL) { + tlog(TLOG_WARN, "malloc qtype soa table failed."); + return -1; + } + group_rule->soa_table = soa_table; + if (_config_current_rule_group() != NULL) { - memcpy(&group_rule->check_orders, &_config_current_group()->rule->check_orders, sizeof(group_rule->check_orders)); - memcpy(&group_rule->ipset_nftset, &_config_current_group()->rule->ipset_nftset, sizeof(group_rule->ipset_nftset)); - return; + /* copy parent group data. */ + memcpy(&group_rule->copy_data_section_begin, &_config_current_rule_group()->copy_data_section_begin, + offsetof(struct dns_conf_group, copy_data_section_end) - + offsetof(struct dns_conf_group, copy_data_section_begin)); + memcpy(group_rule->soa_table, _config_current_rule_group()->soa_table, soa_talbe_size); + return 0; } + memset(soa_table, 0, soa_talbe_size); memcpy(&group_rule->check_orders, &dns_conf_default_check_orders, sizeof(group_rule->check_orders)); + group_rule->dualstack_ip_selection = 1; + + return 0; } static int _config_current_group_push(const char *group_name) @@ -1090,6 +1103,8 @@ static void _config_rule_group_remove(struct dns_conf_group *rule_group) art_tree_destroy(&rule_group->domain_rule.tree); Destroy_Radix(rule_group->address_rule.ipv4, _config_ip_iter_free, NULL); Destroy_Radix(rule_group->address_rule.ipv6, _config_ip_iter_free, NULL); + free(rule_group->soa_table); + free(rule_group); } @@ -2429,6 +2444,14 @@ static int _config_speed_check_mode(void *data, int argc, char *argv[]) return _config_speed_check_mode_parser(&_config_current_rule_group()->check_orders, mode); } +static int _config_dualstack_ip_selection(void *data, int argc, char *argv[]) +{ + struct config_item_yesno item; + + item.data = &_config_current_rule_group()->dualstack_ip_selection; + return conf_yesno(NULL, &item, argc, argv); +} + static int _config_dns64(void *data, int argc, char *argv[]) { prefix_t prefix; @@ -3318,7 +3341,15 @@ static int _config_client_rule_add(const char *ip_cidr, enum client_rule type, v return -1; } -static int _config_qtype_soa(void *data, int argc, char *argv[]) +static int _config_force_AAAA_soa(void *data, int argc, char *argv[]) +{ + struct config_item_yesno item; + + item.data = &_config_current_rule_group()->force_AAAA_SOA; + return conf_yesno(NULL, &item, argc, argv); +} + +static int _conf_qtype_soa(uint8_t *soa_table, int argc, char *argv[]) { int i = 0; int j = 0; @@ -3354,7 +3385,7 @@ static int _config_qtype_soa(void *data, int argc, char *argv[]) for (j = start; j <= end; j++) { int offset = j / 8; int bit = j % 8; - dns_qtype_soa_table[offset] |= (1 << bit); + soa_table[offset] |= (1 << bit); } } } @@ -3362,12 +3393,9 @@ static int _config_qtype_soa(void *data, int argc, char *argv[]) return 0; } -static void _config_qtype_soa_table_destroy(void) +static int _config_qtype_soa(void *data, int argc, char *argv[]) { - if (dns_qtype_soa_table) { - free(dns_qtype_soa_table); - dns_qtype_soa_table = NULL; - } + return _conf_qtype_soa(_config_current_rule_group()->soa_table, argc, argv); } static void _config_domain_set_name_table_destroy(void) @@ -5276,7 +5304,7 @@ static struct config_item _config_item[] = { CONF_INT("serve-expired-ttl", &dns_conf_serve_expired_ttl, 0, CONF_INT_MAX), CONF_INT("serve-expired-reply-ttl", &dns_conf_serve_expired_reply_ttl, 0, CONF_INT_MAX), CONF_INT("serve-expired-prefetch-time", &dns_conf_serve_expired_prefetch_time, 0, CONF_INT_MAX), - CONF_YESNO("dualstack-ip-selection", &dns_conf_dualstack_ip_selection), + CONF_CUSTOM("dualstack-ip-selection", _config_dualstack_ip_selection, NULL), CONF_YESNO("dualstack-ip-allow-force-AAAA", &dns_conf_dualstack_ip_allow_force_AAAA), CONF_INT("dualstack-ip-selection-threshold", &dns_conf_dualstack_ip_selection_threshold, 0, 1000), CONF_CUSTOM("dns64", _config_dns64, NULL), @@ -5304,7 +5332,7 @@ static struct config_item _config_item[] = { CONF_INT("max-reply-ip-num", &dns_conf_max_reply_ip_num, 1, CONF_INT_MAX), CONF_INT("max-query-limit", &dns_conf_max_query_limit, 0, CONF_INT_MAX), CONF_ENUM("response-mode", &dns_conf_response_mode, &dns_conf_response_mode_enum), - CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA), + CONF_CUSTOM("force-AAAA-SOA", _config_force_AAAA_soa, NULL), CONF_YESNO("force-no-CNAME", &dns_conf_force_no_cname), CONF_CUSTOM("force-qtype-SOA", _config_qtype_soa, NULL), CONF_CUSTOM("blacklist-ip", _config_blacklist_ip, NULL), @@ -5505,12 +5533,6 @@ static int _dns_server_load_conf_init(void) hash_init(dns_ipset_table.ipset); hash_init(dns_nftset_table.nftset); - 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); @@ -5566,7 +5588,6 @@ void dns_server_load_exit(void) _config_group_table_destroy(); _config_ptr_table_destroy(0); _config_host_table_destroy(0); - _config_qtype_soa_table_destroy(); _config_proxy_table_destroy(); _config_srv_record_table_destroy(); diff --git a/src/dns_conf.h b/src/dns_conf.h index a138518f6e..846364bd26 100644 --- a/src/dns_conf.h +++ b/src/dns_conf.h @@ -417,8 +417,13 @@ 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; + char copy_data_section_begin[0]; struct dns_conf_ipset_nftset ipset_nftset; struct dns_domain_check_orders check_orders; + int force_AAAA_SOA; + int dualstack_ip_selection; + char copy_data_section_end[0]; const char *group_name; }; @@ -470,8 +475,6 @@ struct dns_bind_ip { struct nftset_ipset_rules nftset_ipset_rule; }; -extern uint8_t *dns_qtype_soa_table; - struct dns_domain_set_rule { struct list_head list; enum domain_rule type; @@ -635,7 +638,6 @@ extern char dns_conf_server_name[DNS_MAX_SERVER_NAME_LEN]; extern struct dns_conf_domain_rule dns_conf_domain_rule; extern struct dns_conf_client_rule dns_conf_client_rule; -extern int dns_conf_dualstack_ip_selection; extern int dns_conf_dualstack_ip_allow_force_AAAA; extern int dns_conf_dualstack_ip_selection_threshold; @@ -647,7 +649,6 @@ extern int dns_conf_rr_ttl; extern int dns_conf_rr_ttl_reply_max; extern int dns_conf_rr_ttl_min; extern int dns_conf_rr_ttl_max; -extern int dns_conf_force_AAAA_SOA; extern int dns_conf_nftset_debug_enable; extern int dns_conf_local_ttl; extern int dns_conf_mdns_lookup; diff --git a/src/dns_server.c b/src/dns_server.c index 2db251a633..170251d40b 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -583,7 +583,7 @@ static void _dns_server_set_dualstack_selection(struct dns_request *request) return; } - request->dualstack_selection = dns_conf_dualstack_ip_selection; + request->dualstack_selection = request->conf->dualstack_ip_selection; } static int _dns_server_is_return_soa_qtype(struct dns_request *request, dns_type_t qtype) @@ -639,7 +639,7 @@ static int _dns_server_is_return_soa_qtype(struct dns_request *request, dns_type } if (qtype == DNS_T_AAAA) { - if (_dns_server_has_bind_flag(request, BIND_FLAG_FORCE_AAAA_SOA) == 0 || dns_conf_force_AAAA_SOA == 1) { + if (_dns_server_has_bind_flag(request, BIND_FLAG_FORCE_AAAA_SOA) == 0 || request->conf->force_AAAA_SOA == 1) { return 1; } @@ -2816,7 +2816,7 @@ static struct dns_request *_dns_server_new_request(void) atomic_set(&request->do_callback, 0); request->ping_time = -1; request->prefetch = 0; - request->dualstack_selection = dns_conf_dualstack_ip_selection; + request->dualstack_selection = 0; request->dualstack_selection_ping_time = -1; request->rcode = DNS_RC_SERVFAIL; request->conn = NULL; @@ -5327,14 +5327,14 @@ static int _dns_server_process_dns64(struct dns_request *request) static int _dns_server_qtype_soa(struct dns_request *request) { - if (request->skip_qtype_soa || dns_qtype_soa_table == NULL) { + if (request->skip_qtype_soa || request->conf->soa_table == NULL) { return -1; } 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) { + if ((request->conf->soa_table[offset] & (1 << bit)) == 0) { return -1; } } diff --git a/test/cases/test-group.cc b/test/cases/test-group.cc index 9767193385..2d8bbf72ab 100644 --- a/test/cases/test-group.cc +++ b/test/cases/test-group.cc @@ -225,3 +225,163 @@ server udp://127.0.0.1:61053 EXPECT_EQ(client.GetAnswer()[0].GetData(), "7.8.9.10"); } } + +TEST_F(Group, conf_inherit) +{ + smartdns::MockServer server_upstream; + smartdns::Server server; + std::string file = "/tmp/smartdns_conf_file" + smartdns::GenerateRandomString(5) + ".conf"; + std::ofstream ofs(file); + ASSERT_TRUE(ofs.is_open()); + Defer + { + ofs.close(); + unlink(file.c_str()); + }; + + ofs << R"""( +server udp://127.0.0.1:61053 -e +client-rules 127.0.0.1 +)"""; + ofs.flush(); + + server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) { + if (request->qtype == DNS_T_AAAA) { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700); + return smartdns::SERVER_REQUEST_OK; + } else if (request->qtype == DNS_T_A) { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611); + smartdns::MockServer::AddIP(request, request->domain.c_str(), "7.8.9.10", 611); + return smartdns::SERVER_REQUEST_OK; + } else if (request->qtype == DNS_T_TXT) { + dns_add_TXT(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 6, "hello world"); + return smartdns::SERVER_REQUEST_OK; + } else { + return smartdns::SERVER_REQUEST_SOA; + } + }); + + /* this ip will be discard, but is reachable */ + server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 50); + server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 10); + server.MockPing(PING_TYPE_ICMP, "64:ff9b::102:304", 60, 10); + + server.Start(R"""(bind [::]:60053 +server udp://127.0.0.1:61053 +group-begin dummy +speed-check-mode none +force-AAAA-SOA yes +force-qtype-SOA 16 +conf-file /tmp/smartdns_conf_file*.conf -g client +)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.com", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 2); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4"); + EXPECT_EQ(client.GetAnswer()[1].GetData(), "7.8.9.10"); + + ASSERT_TRUE(client.Query("b.com AAAA", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + + ASSERT_TRUE(client.Query("c.com TXT", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + + auto ipaddr = smartdns::GetAvailableIPAddresses(); + if (ipaddr.size() > 0) { + ASSERT_TRUE(client.Query("a.com", 60053, ipaddr[0])); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "7.8.9.10"); + + ASSERT_TRUE(client.Query("b.com AAAA", 60053, ipaddr[0])); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.com"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::102:304"); + + ASSERT_TRUE(client.Query("c.com TXT", 60053, ipaddr[0])); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "c.com"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "\"hello world\""); + } +} + +TEST_F(Group, dualstack_inherit_ipv4_prefer) +{ + 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"); + smartdns::MockServer::AddIP(request, request->domain.c_str(), "5.6.7.8"); + return smartdns::SERVER_REQUEST_OK; + } else 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, 80); + server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 110); + server.MockPing(PING_TYPE_ICMP, "2001:db8::1", 60, 150); + server.MockPing(PING_TYPE_ICMP, "2001:db8::2", 60, 200); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +speed-check-mode ping +group-begin dummy +group-begin client +dualstack-ip-selection no +client-rules 127.0.0.1 +)"""); + 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].GetData(), "2001:db8::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(), 3); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4"); + + auto ipaddr = smartdns::GetAvailableIPAddresses(); + if (ipaddr.size() > 0) { + ASSERT_TRUE(client.Query("a.com AAAA", 60053, ipaddr[0])); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAuthorityNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAuthority()[0].GetName(), "a.com"); + EXPECT_EQ(client.GetAuthority()[0].GetTTL(), 3); + EXPECT_EQ(client.GetAuthority()[0].GetType(), "SOA"); + + ASSERT_TRUE(client.Query("a.com", 60053, ipaddr[0])); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_LT(client.GetQueryTime(), 20); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com"); + EXPECT_GT(client.GetAnswer()[0].GetTTL(), 597); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4"); + } +}