Jelajahi Sumber

dns_conf: bind speed-check-mode, force-qtype-soa with group.

Nick Peng 1 tahun lalu
induk
melakukan
8c423fece0
4 mengubah file dengan 215 tambahan dan 33 penghapusan
  1. 45 24
      src/dns_conf.c
  2. 5 4
      src/dns_conf.h
  3. 5 5
      src/dns_server.c
  4. 160 0
      test/cases/test-group.cc

+ 45 - 24
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 @@ errout:
 	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();
 

+ 5 - 4
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;

+ 5 - 5
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 @@ errout:
 
 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;
 		}
 	}

+ 160 - 0
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");
+	}
+}