Ver código fonte

dns_server: fix type65 issue

Nick Peng 1 ano atrás
pai
commit
d4bb3d7ee7
2 arquivos alterados com 278 adições e 23 exclusões
  1. 72 23
      src/dns_server.c
  2. 206 0
      test/cases/test-https.cc

+ 72 - 23
src/dns_server.c

@@ -744,6 +744,10 @@ static int _dns_server_is_return_soa_qtype(struct dns_request *request, dns_type
 			request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV4] == NULL) {
 			return 1;
 		}
+	} else if (qtype == DNS_T_HTTPS) {
+		if (request->domain_rule.rules[DOMAIN_RULE_HTTPS] == NULL) {
+			return 1;
+		}
 	}
 
 	return 0;
@@ -4017,7 +4021,7 @@ static int _dns_server_process_answer_HTTPS(struct dns_rrs *rrs, struct dns_requ
 }
 
 static int _dns_server_process_answer(struct dns_request *request, const char *domain, struct dns_packet *packet,
-									  unsigned int result_flag)
+									  unsigned int result_flag, int *need_passthrouh)
 {
 	int ttl = 0;
 	char name[DNS_MAX_CNAME_LEN] = {0};
@@ -4045,6 +4049,28 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
 		return DNS_CLIENT_ACTION_UNDEFINE;
 	}
 
+	/* when QTYPE is HTTPS, check if support */
+	if (request->qtype == DNS_T_HTTPS) {
+		int https_svcb_record_num = 0;
+		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_HTTPS: {
+					https_svcb_record_num++;
+					if (https_svcb_record_num <= 1) {
+						continue;
+					}
+
+					/* CURRENT NOT SUPPORT MUTI HTTPS RECORD */
+					*need_passthrouh = 1;
+					return DNS_CLIENT_ACTION_OK;
+				}
+				}
+			}
+		}
+	}
+
 	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)) {
@@ -4099,6 +4125,10 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
 					continue;
 				}
 				request->rcode = packet->head.rcode;
+				if (request->has_ip == 0) {
+					request->passthrough = 1;
+					_dns_server_request_complete(request);
+				}
 			} break;
 			case DNS_T_SOA: {
 				/* if DNS64 enabled, skip check SOA. */
@@ -4552,12 +4582,36 @@ static void _dns_server_passthrough_may_complete(struct dns_request *request)
 	_dns_server_request_complete_with_all_IPs(request, 1);
 }
 
+static int _dns_server_resolve_callback_reply_passthrough(struct dns_request *request, const char *domain,
+														  struct dns_packet *packet, unsigned char *inpacket,
+														  int inpacket_len, unsigned int result_flag)
+{
+	struct dns_server_post_context context;
+	int ttl = 0;
+	int ret = 0;
+
+	ret = _dns_server_passthrough_rule_check(request, domain, packet, result_flag, &ttl);
+	if (ret == 0) {
+		return 0;
+	}
+
+	ttl = _dns_server_get_conf_ttl(request, ttl);
+	_dns_server_post_context_init_from(&context, request, packet, inpacket, inpacket_len);
+	context.do_cache = 1;
+	context.do_audit = 1;
+	context.do_reply = 1;
+	context.do_ipset = 1;
+	context.reply_ttl = ttl;
+	return _dns_server_reply_passthrough(&context);
+}
+
 static int dns_server_resolve_callback(const char *domain, dns_result_type rtype, struct dns_server_info *server_info,
 									   struct dns_packet *packet, unsigned char *inpacket, int inpacket_len,
 									   void *user_ptr)
 {
 	struct dns_request *request = user_ptr;
 	int ret = 0;
+	int need_passthrouh = 0;
 	unsigned long result_flag = dns_client_server_result_flag(server_info);
 
 	if (request == NULL) {
@@ -4570,21 +4624,8 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
 			 dns_client_get_server_type(server_info), domain, request->qtype, packet->head.rcode, request->id);
 
 		if (request->passthrough == 1 && atomic_read(&request->notified) == 0) {
-			struct dns_server_post_context context;
-			int ttl = 0;
-			ret = _dns_server_passthrough_rule_check(request, domain, packet, result_flag, &ttl);
-			if (ret == 0) {
-				return 0;
-			}
-
-			ttl = _dns_server_get_conf_ttl(request, ttl);
-			_dns_server_post_context_init_from(&context, request, packet, inpacket, inpacket_len);
-			context.do_cache = 1;
-			context.do_audit = 1;
-			context.do_reply = 1;
-			context.do_ipset = 1;
-			context.reply_ttl = ttl;
-			return _dns_server_reply_passthrough(&context);
+			return _dns_server_resolve_callback_reply_passthrough(request, domain, packet, inpacket, inpacket_len,
+																  result_flag);
 		}
 
 		if (request->prefetch == 0 && request->response_mode == DNS_RESPONSE_MODE_FASTEST_RESPONSE &&
@@ -4614,7 +4655,13 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
 			}
 		}
 
-		ret = _dns_server_process_answer(request, domain, packet, result_flag);
+		ret = _dns_server_process_answer(request, domain, packet, result_flag, &need_passthrouh);
+		if (ret == 0 && need_passthrouh == 1 && atomic_read(&request->notified) == 0) {
+			/* not supported record, passthrouth */
+			request->passthrough = 1;
+			return _dns_server_resolve_callback_reply_passthrough(request, domain, packet, inpacket, inpacket_len,
+																  result_flag);
+		}
 		_dns_server_passthrough_may_complete(request);
 		return ret;
 	} else if (rtype == DNS_QUERY_ERR) {
@@ -5421,14 +5468,10 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request)
 
 	/* get domain rule flag */
 	rule_flag = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS);
-	if (rule_flag == NULL) {
-		if (_dns_server_is_return_soa(request)) {
-			goto soa;
-		}
-		goto out;
+	if (rule_flag != NULL) {
+		flags = rule_flag->flags;
 	}
 
-	flags = rule_flag->flags;
 	if (flags & DOMAIN_FLAG_NO_SERVE_EXPIRED) {
 		request->no_serve_expired = 1;
 	}
@@ -5474,6 +5517,7 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request)
 			}
 			goto soa;
 		}
+		goto out;
 		break;
 	case DNS_T_AAAA:
 		if (flags & DOMAIN_FLAG_ADDR_IPV6_IGN) {
@@ -5501,6 +5545,7 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request)
 			/* if IPV4 return SOA and dualstack-selection enabled, set request dualstack disable */
 			request->dualstack_selection = 0;
 		}
+		goto out;
 		break;
 	case DNS_T_HTTPS:
 		if (flags & DOMAIN_FLAG_ADDR_HTTPS_IGN) {
@@ -5522,6 +5567,10 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request)
 			}
 		}
 
+		if (request->domain_rule.rules[DOMAIN_RULE_HTTPS] != NULL) {
+			goto skip_soa_out;
+		}
+
 		goto out;
 		break;
 	default:

+ 206 - 0
test/cases/test-https.cc

@@ -391,6 +391,69 @@ cache-persist no)""");
 	EXPECT_EQ(client.GetAnswer()[0].GetData(), "1 a.com. alpn=\"h2,h3-19\" port=443 ipv4hint=1.2.3.4 ech=AEX+DQA=");
 }
 
+TEST_F(HTTPS, HTTPS_IGN_WITH_RULE)
+{
+	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_HTTPS) {
+			return smartdns::SERVER_REQUEST_SOA;
+		}
+
+		struct dns_packet *packet = request->response_packet;
+		struct dns_rr_nested svcparam_buffer;
+
+		dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "a.com");
+		const char alph[] = "\x02h2\x05h3-19";
+		int alph_len = sizeof(alph) - 1;
+		dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
+		dns_HTTPS_add_port(&svcparam_buffer, 443);
+		unsigned char add_v4[] = {1, 2, 3, 4};
+		unsigned char *addr[1] = {add_v4};
+		dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
+		unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
+		dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
+		unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+		addr[0] = add_v6;
+		dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
+		dns_add_HTTPS_end(&svcparam_buffer);
+
+		return smartdns::SERVER_REQUEST_OK;
+	});
+
+	server.Start(R"""(bind [::]:60053
+server 127.0.0.1:61053
+log-console yes
+dualstack-ip-selection no
+force-qtype-SOA 65
+https-record /a.com/noipv4hint,noipv6hint
+log-level debug
+cache-persist no)""");
+	smartdns::Client client;
+
+	ASSERT_TRUE(client.Query("b.com HTTPS", 60053));
+	std::cout << client.GetResult() << std::endl;
+	ASSERT_EQ(client.GetAuthorityNum(), 1);
+	EXPECT_EQ(client.GetStatus(), "NOERROR");
+	EXPECT_EQ(client.GetAuthority()[0].GetName(), "b.com");
+	EXPECT_EQ(client.GetAuthority()[0].GetTTL(), 30);
+	EXPECT_EQ(client.GetAuthority()[0].GetType(), "SOA");
+
+	ASSERT_TRUE(client.Query("a.com HTTPS", 61053));
+	std::cout << client.GetResult() << std::endl;
+	ASSERT_EQ(client.GetAnswerNum(), 1);
+	auto result_check = client.GetAnswer()[0].GetData();
+
+	ASSERT_TRUE(client.Query("a.com HTTPS", 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].GetType(), "HTTPS");
+	EXPECT_EQ(client.GetAnswer()[0].GetData(), "1 a.com. alpn=\"h2,h3-19\" port=443 ech=AEX+DQA=");
+}
+
 TEST_F(HTTPS, HTTPS_DOMAIN_RULE_IGN)
 {
 	smartdns::MockServer server_upstream;
@@ -538,3 +601,146 @@ cache-persist no)""");
 	EXPECT_EQ(client.GetAnswer()[0].GetType(), "HTTPS");
 	EXPECT_EQ(client.GetAnswer()[0].GetData(), "1 b.com. alpn=\"h2,h3-19\" port=443 ech=AEX+DQA=");
 }
+
+TEST_F(HTTPS, multi_not_support)
+{
+	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_HTTPS) {
+			return smartdns::SERVER_REQUEST_SOA;
+		}
+
+		struct dns_packet *packet = request->response_packet;
+		struct dns_rr_nested svcparam_buffer;
+
+		{
+			dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "b.com");
+			const char alph[] = "\x02h2\x05h3-19";
+			int alph_len = sizeof(alph) - 1;
+			dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
+			dns_HTTPS_add_port(&svcparam_buffer, 443);
+			unsigned char add_v4[] = {1, 2, 3, 4};
+			unsigned char *addr[1] = {add_v4};
+			dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
+			unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
+			dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
+			unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+			addr[0] = add_v6;
+			dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
+			dns_add_HTTPS_end(&svcparam_buffer);
+		}
+
+		{
+
+			dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "c.com");
+			const char alph[] = "\x02h2\x05h3-19";
+			int alph_len = sizeof(alph) - 1;
+			dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
+			dns_HTTPS_add_port(&svcparam_buffer, 443);
+			unsigned char add_v4[] = {5, 6, 7, 8};
+			unsigned char *addr[1] = {add_v4};
+			dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
+			unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
+			dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
+			unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17};
+			addr[0] = add_v6;
+			dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
+			dns_add_HTTPS_end(&svcparam_buffer);
+		}
+
+		return smartdns::SERVER_REQUEST_OK;
+	});
+
+	server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
+	server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 10);
+	server.Start(R"""(bind [::]:60053
+server 127.0.0.1:61053
+log-console yes
+dualstack-ip-selection no
+https-record noipv4hint,noipv6hint
+log-level debug
+cache-persist no)""");
+	smartdns::Client client;
+	ASSERT_TRUE(client.Query("a.com HTTPS", 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].GetTTL(), 600);
+	EXPECT_EQ(client.GetAnswer()[0].GetType(), "HTTPS");
+	EXPECT_EQ(
+		client.GetAnswer()[0].GetData(),
+		"1 b.com. alpn=\"h2,h3-19\" port=443 ipv4hint=1.2.3.4 ech=AEX+DQA= ipv6hint=102:304:506:708:90a:b0c:d0e:f10");
+
+	EXPECT_EQ(client.GetAnswer()[1].GetName(), "a.com");
+	EXPECT_EQ(client.GetAnswer()[1].GetTTL(), 600);
+	EXPECT_EQ(client.GetAnswer()[1].GetType(), "HTTPS");
+	EXPECT_EQ(
+		client.GetAnswer()[1].GetData(),
+		"1 c.com. alpn=\"h2,h3-19\" port=443 ipv4hint=5.6.7.8 ech=AEX+DQA= ipv6hint=102:304:506:708:90a:b0c:d0e:f11");
+}
+
+TEST_F(HTTPS, BIND_FORCE_SOA)
+{
+	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_HTTPS) {
+			smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
+			return smartdns::SERVER_REQUEST_OK;
+		}
+
+		if (request->qtype != DNS_T_HTTPS) {
+			return smartdns::SERVER_REQUEST_SOA;
+		}
+
+		struct dns_packet *packet = request->response_packet;
+		struct dns_rr_nested svcparam_buffer;
+
+		dns_add_HTTPS_start(&svcparam_buffer, packet, DNS_RRS_AN, request->domain.c_str(), 3, 1, "a.com");
+		const char alph[] = "\x02h2\x05h3-19";
+		int alph_len = sizeof(alph) - 1;
+		dns_HTTPS_add_alpn(&svcparam_buffer, alph, alph_len);
+		dns_HTTPS_add_port(&svcparam_buffer, 443);
+		unsigned char add_v4[] = {1, 2, 3, 4};
+		unsigned char *addr[1] = {add_v4};
+		dns_HTTPS_add_ipv4hint(&svcparam_buffer, addr, 1);
+		unsigned char ech[] = {0x00, 0x45, 0xfe, 0x0d, 0x00};
+		dns_HTTPS_add_ech(&svcparam_buffer, (void *)ech, sizeof(ech));
+		unsigned char add_v6[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+		addr[0] = add_v6;
+		dns_HTTPS_add_ipv6hint(&svcparam_buffer, addr, 1);
+		dns_add_HTTPS_end(&svcparam_buffer);
+
+		return smartdns::SERVER_REQUEST_OK;
+	});
+
+	server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 100);
+
+	server.Start(R"""(bind [::]:60053
+bind [::]:62053 -force-https-soa
+server 127.0.0.1:61053
+log-console yes
+dualstack-ip-selection no
+log-level debug
+cache-persist no)""");
+	smartdns::Client client;
+	ASSERT_TRUE(client.Query("a.com HTTPS", 62053));
+	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(), 30);
+	EXPECT_EQ(client.GetAuthority()[0].GetType(), "SOA");
+
+	ASSERT_TRUE(client.Query("a.com HTTPS", 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].GetType(), "HTTPS");
+	EXPECT_EQ(client.GetAnswer()[0].GetData(), "1 a.com. alpn=\"h2,h3-19\" port=443 ipv4hint=1.2.3.4 ech=AEX+DQA=");
+}