From 1a17da726dad28cfc3527c36e8f96fbc06d7e489 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Fri, 15 Dec 2023 23:03:43 +0800 Subject: [PATCH] address: force anoter A/AAAA SOA when ip is set. --- src/dns_server.c | 23 +++- test/cases/test-address.cc | 210 ++++++++++++++++++++++++++++++++++- test/cases/test-dualstack.cc | 49 ++++++++ 3 files changed, 278 insertions(+), 4 deletions(-) diff --git a/src/dns_server.c b/src/dns_server.c index 57522b7..c8ba3bb 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -624,6 +624,16 @@ static int _dns_server_is_return_soa_qtype(struct dns_request *request, dns_type if (_dns_server_has_bind_flag(request, BIND_FLAG_FORCE_AAAA_SOA) == 0 || dns_conf_force_AAAA_SOA == 1) { return 1; } + + if (request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV4] != NULL && + request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV6] == NULL) { + return 1; + } + } else if (qtype == DNS_T_A) { + if (request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV6] != NULL && + request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV4] == NULL) { + return 1; + } } return 0; @@ -4440,7 +4450,12 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request) } if (_dns_server_is_return_soa(request)) { - /* return SOA for A request */ + /* if AAAA exists, return SOA with NOERROR*/ + if (request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV6] != NULL) { + goto soa; + } + + /* if AAAA not exists, return SOA with NXDOMAIN */ if (_dns_server_is_return_soa_qtype(request, DNS_T_AAAA)) { rcode = DNS_RC_NXDOMAIN; } @@ -4458,7 +4473,11 @@ static int _dns_server_pre_process_rule_flags(struct dns_request *request) } if (_dns_server_is_return_soa(request)) { - /* return SOA for A request */ + /* if A exists, return SOA with NOERROR*/ + if (request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV4] != NULL) { + goto soa; + } + /* if A not exists, return SOA with NXDOMAIN */ if (_dns_server_is_return_soa_qtype(request, DNS_T_A)) { rcode = DNS_RC_NXDOMAIN; } diff --git a/test/cases/test-address.cc b/test/cases/test-address.cc index b52ece4..d496270 100644 --- a/test/cases/test-address.cc +++ b/test/cases/test-address.cc @@ -291,10 +291,216 @@ cache-persist no)"""); ASSERT_TRUE(client.Query("a.com AAAA", 60053)); std::cout << client.GetResult() << std::endl; ASSERT_EQ(client.GetAnswerNum(), 0); - EXPECT_EQ(client.GetStatus(), "NXDOMAIN"); + EXPECT_EQ(client.GetStatus(), "NOERROR"); ASSERT_TRUE(client.Query("b.com A", 60053)); std::cout << client.GetResult() << std::endl; ASSERT_EQ(client.GetAnswerNum(), 0); EXPECT_EQ(client.GetStatus(), "NXDOMAIN"); -} \ No newline at end of file +} + +TEST_F(Address, set_ipv4_query_ipv6) +{ + 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", 700); + return smartdns::SERVER_REQUEST_OK; + } else if (request->qtype == DNS_T_AAAA) { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700); + return smartdns::SERVER_REQUEST_OK; + } + return smartdns::SERVER_REQUEST_SOA; + }); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +log-num 0 +log-console yes +log-level debug +speed-check-mode none +address /a.com/192.168.1.1 +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.com A", 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(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "A"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "192.168.1.1"); + + ASSERT_TRUE(client.Query("a.com AAAA", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NOERROR"); +} + +TEST_F(Address, set_ipv6_query_ipv4) +{ + 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", 700); + return smartdns::SERVER_REQUEST_OK; + } else if (request->qtype == DNS_T_AAAA) { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700); + return smartdns::SERVER_REQUEST_OK; + } + return smartdns::SERVER_REQUEST_SOA; + }); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +log-num 0 +log-console yes +log-level debug +speed-check-mode none +address /a.com/64:ff9b::1010:1010 +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.com A", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + + 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(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::1010:1010"); +} + +TEST_F(Address, set_ipv4_allow_ipv6) +{ + 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", 700); + return smartdns::SERVER_REQUEST_OK; + } else if (request->qtype == DNS_T_AAAA) { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700); + return smartdns::SERVER_REQUEST_OK; + } + return smartdns::SERVER_REQUEST_SOA; + }); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +log-num 0 +log-console yes +log-level debug +speed-check-mode none +address /a.com/192.168.1.1 +address /b.a.com/-6 +address /com/# +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.com A", 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(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "A"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "192.168.1.1"); + + ASSERT_TRUE(client.Query("a.com AAAA", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + + ASSERT_TRUE(client.Query("c.a.com AAAA", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + + ASSERT_TRUE(client.Query("b.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(), "b.a.com"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::102:304"); + + ASSERT_TRUE(client.Query("b.com AAAA", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NXDOMAIN"); +} + +TEST_F(Address, set_both_ipv4_ipv6) +{ + 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", 700); + return smartdns::SERVER_REQUEST_OK; + } else if (request->qtype == DNS_T_AAAA) { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700); + return smartdns::SERVER_REQUEST_OK; + } + return smartdns::SERVER_REQUEST_SOA; + }); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +log-num 0 +log-console yes +log-level debug +speed-check-mode none +address /a.com/192.168.1.1 +address /b.a.com/64:ff9b::1010:1010 +address /com/# +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.com A", 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(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "A"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "192.168.1.1"); + + ASSERT_TRUE(client.Query("c.a.com AAAA", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + + ASSERT_TRUE(client.Query("b.a.com A", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.a.com"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "A"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "192.168.1.1"); + + ASSERT_TRUE(client.Query("b.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(), "b.a.com"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::1010:1010"); + + ASSERT_TRUE(client.Query("b.com AAAA", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 0); + EXPECT_EQ(client.GetStatus(), "NXDOMAIN"); +} diff --git a/test/cases/test-dualstack.cc b/test/cases/test-dualstack.cc index 6fb6f68..532ec8e 100644 --- a/test/cases/test-dualstack.cc +++ b/test/cases/test-dualstack.cc @@ -184,3 +184,52 @@ cache-persist no)"""); EXPECT_GT(client.GetAnswer()[0].GetTTL(), 597); EXPECT_EQ(client.GetAnswer()[0].GetData(), "2001:db8::1"); } + +TEST_F(DualStack, ipv6_no_speed) +{ + 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, 100); + server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 110); + server.MockPing(PING_TYPE_ICMP, "2001:db8::1", 60, 10000); + server.MockPing(PING_TYPE_ICMP, "2001:db8::2", 60, 10000); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +log-num 0 +log-console yes +speed-check-mode ping +log-level debug +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("a.com A", 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"); + + usleep(220 * 1000); + ASSERT_TRUE(client.Query("a.com AAAA", 60053)); + 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_GT(client.GetAuthority()[0].GetTTL(), 597); + EXPECT_EQ(client.GetAuthority()[0].GetType(), "SOA"); +} \ No newline at end of file