diff --git a/src/dns_client.c b/src/dns_client.c index ffacc8b..2fddfe3 100644 --- a/src/dns_client.c +++ b/src/dns_client.c @@ -2297,7 +2297,7 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e return 0; } - if (errno == ECONNREFUSED) { + if (errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH) { tlog(TLOG_DEBUG, "recvfrom %s failed, %s\n", server_info->ip, strerror(errno)); goto errout; } @@ -3568,7 +3568,7 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, time(&now); if (now - lastlog > 120) { lastlog = now; - tlog(TLOG_WARN, "Send query %s to upstream server failed, total server number %d", query->domain, + tlog(TLOG_WARN, "send query %s to upstream server failed, total server number %d", query->domain, total_server); } return -1; diff --git a/src/dns_server.c b/src/dns_server.c index 7e677e3..4736f0a 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -311,6 +311,8 @@ struct dns_request { int no_select_possible_ip; int no_cache_cname; int no_cache; + + int has_cname_loop; }; /* dns server data */ @@ -4228,6 +4230,10 @@ static int _dns_server_process_cname_pre(struct dns_request *request) return 0; } + if (request->has_cname_loop == 1) { + return 0; + } + /* get domain rule flag */ rule_flag = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS); if (rule_flag != NULL) { @@ -4267,6 +4273,10 @@ static int _dns_server_process_cname(struct dns_request *request) return 0; } + if (request->has_cname_loop == 1) { + return 0; + } + /* get domain rule flag */ rule_flag = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS); if (rule_flag != NULL) { @@ -4289,6 +4299,33 @@ static int _dns_server_process_cname(struct dns_request *request) return -1; } + /* check cname rule loop */ + struct dns_request *check_request = child_request->parent_request; + struct dns_cname_rule *child_cname = _dns_server_get_dns_rule(child_request, DOMAIN_RULE_CNAME); + + /* sub domain rule*/ + if (child_cname != NULL && strncmp(child_request->domain, child_cname->cname, DNS_MAX_CNAME_LEN) == 0) { + child_request->domain_rule.rules[DOMAIN_RULE_CNAME] = NULL; + child_request->has_cname_loop = 1; + } + + /* loop rule */ + while (check_request != NULL && child_cname != NULL) { + struct dns_cname_rule *check_cname = _dns_server_get_dns_rule(check_request, DOMAIN_RULE_CNAME); + if (check_cname == NULL) { + break; + } + + if (strstr(child_request->domain, check_request->domain) != NULL && + check_request != child_request->parent_request) { + child_request->domain_rule.rules[DOMAIN_RULE_CNAME] = NULL; + child_request->has_cname_loop = 1; + break; + } + + check_request = check_request->parent_request; + } + child_group_name = _dns_server_get_request_groupname(child_request); if (child_group_name) { /* reset dns group and setup child request domain group again when do query.*/ @@ -5029,6 +5066,7 @@ static int _dns_server_query_dualstack(struct dns_request *request) safe_strncpy(request_dualstack->domain, request->domain, sizeof(request->domain)); request_dualstack->qtype = qtype; request_dualstack->dualstack_selection_query = 1; + request_dualstack->has_cname_loop = request->has_cname_loop; request_dualstack->prefetch = request->prefetch; request_dualstack->prefetch_expired_domain = request->prefetch_expired_domain; _dns_server_request_get(request); diff --git a/test/cases/test-cname.cc b/test/cases/test-cname.cc index 5407407..31f1b31 100644 --- a/test/cases/test-cname.cc +++ b/test/cases/test-cname.cc @@ -63,3 +63,117 @@ cache-persist no)"""); EXPECT_EQ(client.GetAnswer()[0].GetData(), "b.com."); EXPECT_EQ(client.GetAnswer()[1].GetData(), "1.2.3.4"); } + +TEST_F(Cname, subdomain1) +{ + 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) { + return smartdns::SERVER_REQUEST_SOA; + } + + if (request->domain == "s.a.com") { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700); + return smartdns::SERVER_REQUEST_OK; + + } + + smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611); + return smartdns::SERVER_REQUEST_OK; + }); + + server.Start(R"""(bind [::]:60053 +cname /a.com/s.a.com +server 127.0.0.1:61053 +log-num 0 +log-console yes +log-level debug +cache-persist no)"""); + 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(), "s.a.com."); + EXPECT_EQ(client.GetAnswer()[1].GetData(), "4.5.6.7"); +} + +TEST_F(Cname, subdomain2) +{ + 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) { + return smartdns::SERVER_REQUEST_SOA; + } + + if (request->domain == "a.s.a.com") { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700); + return smartdns::SERVER_REQUEST_OK; + + } + + smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611); + return smartdns::SERVER_REQUEST_OK; + }); + + server.Start(R"""(bind [::]:60053 +cname /a.com/s.a.com +cname /s.a.com/a.s.a.com +server 127.0.0.1:61053 +log-num 0 +log-console yes +log-level debug +cache-persist no)"""); + 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(), "s.a.com."); + EXPECT_EQ(client.GetAnswer()[1].GetData(), "4.5.6.7"); +} + + +TEST_F(Cname, loop) +{ + 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) { + return smartdns::SERVER_REQUEST_SOA; + } + + if (request->domain == "s.a.com") { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700); + return smartdns::SERVER_REQUEST_OK; + + } + + smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611); + return smartdns::SERVER_REQUEST_OK; + }); + + server.Start(R"""(bind [::]:60053 +cname /a.com/c.a.com +cname /c.a.com/s.a.com +server 127.0.0.1:61053 +log-num 0 +log-console yes +log-level debug +cache-persist no)"""); + 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(), "c.a.com."); + EXPECT_EQ(client.GetAnswer()[1].GetData(), "4.5.6.7"); +}