diff --git a/src/Makefile b/src/Makefile index 3d21964..c5edf90 100644 --- a/src/Makefile +++ b/src/Makefile @@ -21,7 +21,7 @@ OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_co # cflags ifndef CFLAGS ifdef DEBUG - CFLAGS = -g + CFLAGS = -g -DDEBUG else CFLAGS = -O2 endif diff --git a/src/dns.c b/src/dns.c index b88051d..c2b0700 100644 --- a/src/dns.c +++ b/src/dns.c @@ -849,7 +849,7 @@ int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned return _dns_get_RAW(rrs, domain, maxsize, ttl, addr, &len); } -int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, char *cname) +int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname) { int rr_len = strnlen(cname, DNS_MAX_CNAME_LEN) + 1; return _dns_add_RAW(packet, type, DNS_T_PTR, domain, ttl, cname, rr_len); @@ -1862,7 +1862,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign while (context->ptr - start < rr_len) { if (_dns_left_len(context) < 4) { - tlog(TLOG_WARN, "data length is invalid, %d:%d", _dns_left_len(context), + tlog(TLOG_DEBUG, "data length is invalid, %d:%d", _dns_left_len(context), (int)(context->ptr - context->data)); return -1; } @@ -1870,7 +1870,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign opt_len = _dns_read_short(&context->ptr); if (_dns_left_len(context) < opt_len) { - tlog(TLOG_ERROR, "read opt data failed, opt_code = %d, opt_len = %d", opt_code, opt_len); + tlog(TLOG_DEBUG, "read opt data failed, opt_code = %d, opt_len = %d", opt_code, opt_len); return -1; } diff --git a/src/dns.h b/src/dns.h index c94dba9..49a7ed8 100644 --- a/src/dns.h +++ b/src/dns.h @@ -257,7 +257,7 @@ int dns_add_A(struct dns_packet *packet, dns_rr_type type, const char *domain, i unsigned char addr[DNS_RR_A_LEN]); int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_A_LEN]); -int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, char *cname); +int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname); int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size); int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, diff --git a/src/dns_client.c b/src/dns_client.c index b5d9436..48f84a2 100644 --- a/src/dns_client.c +++ b/src/dns_client.c @@ -1814,7 +1814,7 @@ static int _dns_client_create_socket_udp(struct dns_server_info *server_info) if (connect(fd, &server_info->addr, server_info->ai_addrlen) != 0) { if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED) { - tlog(TLOG_WARN, "connect %s failed, %s", server_info->ip, strerror(errno)); + tlog(TLOG_INFO, "connect %s failed, %s", server_info->ip, strerror(errno)); goto errout; } @@ -3375,6 +3375,7 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet, if (server_info->fd <= 0) { ret = _dns_client_create_socket(server_info); if (ret != 0) { + server_info->prohibit = 1; continue; } } diff --git a/test/cases/test-address.cc b/test/cases/test-address.cc index a676dec..6f63797 100644 --- a/test/cases/test-address.cc +++ b/test/cases/test-address.cc @@ -161,50 +161,3 @@ cache-persist no)"""); EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA"); EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::1010:1010"); } - -TEST_F(Address, ptr) -{ - 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 -expand-ptr-from-address yes -address /a.com/10.11.12.13 -address /a.com/64:ff9b::1010:1010 -cache-persist no)"""); - smartdns::Client client; - ASSERT_TRUE(client.Query("13.12.11.10.in-addr.arpa PTR", 60053)); - std::cout << client.GetResult() << std::endl; - ASSERT_EQ(client.GetAnswerNum(), 1); - EXPECT_EQ(client.GetStatus(), "NOERROR"); - EXPECT_EQ(client.GetAnswer()[0].GetName(), "13.12.11.10.in-addr.arpa"); - EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600); - EXPECT_EQ(client.GetAnswer()[0].GetType(), "PTR"); - EXPECT_EQ(client.GetAnswer()[0].GetData(), "a.com."); - - ASSERT_TRUE(client.Query("0.1.0.1.0.1.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.9.f.f.4.6.0.0.ip6.arpa PTR", 60053)); - std::cout << client.GetResult() << std::endl; - ASSERT_EQ(client.GetAnswerNum(), 1); - EXPECT_EQ(client.GetStatus(), "NOERROR"); - EXPECT_EQ(client.GetAnswer()[0].GetName(), - "0.1.0.1.0.1.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.9.f.f.4.6.0.0.ip6.arpa"); - EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600); - EXPECT_EQ(client.GetAnswer()[0].GetType(), "PTR"); - EXPECT_EQ(client.GetAnswer()[0].GetData(), "a.com."); -} \ No newline at end of file diff --git a/test/cases/test-bind.cc b/test/cases/test-bind.cc index 92ea314..64f1dfa 100644 --- a/test/cases/test-bind.cc +++ b/test/cases/test-bind.cc @@ -20,6 +20,11 @@ #include "include/utils.h" #include "server.h" #include "gtest/gtest.h" +#include +#include +#include +#include +#include TEST(Bind, tls) { @@ -192,3 +197,58 @@ cache-persist no)"""); EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3); EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4"); } + +TEST(Bind, malformed_packet) +{ + smartdns::MockServer server_upstream; + smartdns::Server server; + + server_upstream.Start("udp://0.0.0.0:62053", [](struct smartdns::ServerRequestContext *request) { + if (request->qtype == DNS_T_A) { + smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4"); + return smartdns::SERVER_REQUEST_OK; + } + return smartdns::SERVER_REQUEST_SOA; + }); + + server.Start(R"""( +bind [::]:60053@lo +server 127.0.0.1:62053 +log-num 0 +log-console yes +log-level info +cache-persist no)"""); + + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + ASSERT_NE(sockfd, -1); + Defer + { + close(sockfd); + }; + + struct sockaddr_in server_addr; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(60053); + server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + for (int i = 0; i < 100000; i++) { + char buf[4096]; + int len = random() % 4096; + if (len <= 0) { + len = 1; + } + + RAND_bytes((unsigned char *)buf, len); + sendto(sockfd, buf, len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)); + } + + smartdns::Client client; + + ASSERT_TRUE(client.Query("a.com", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_LT(client.GetQueryTime(), 100); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4"); +} diff --git a/test/cases/test-ptr.cc b/test/cases/test-ptr.cc new file mode 100644 index 0000000..cd1c063 --- /dev/null +++ b/test/cases/test-ptr.cc @@ -0,0 +1,156 @@ +/************************************************************************* + * + * Copyright (C) 2018-2023 Ruilin Peng (Nick) . + * + * smartdns is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * smartdns is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "client.h" +#include "dns.h" +#include "include/utils.h" +#include "server.h" +#include "util.h" +#include "gtest/gtest.h" +#include + +class Ptr : public ::testing::Test +{ + protected: + virtual void SetUp() {} + virtual void TearDown() {} +}; + +TEST_F(Ptr, query) +{ + 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"); + return smartdns::SERVER_REQUEST_OK; + } + + if (request->qtype == DNS_T_PTR) { + dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname"); + request->response_packet->head.rcode = DNS_RC_NOERROR; + 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 +dualstack-ip-selection no +log-level debug +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("4.3.2.1.in-addr.arpa PTR", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "4.3.2.1.in-addr.arpa"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "PTR"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "my-hostname."); +} + +TEST_F(Ptr, address_expand_ptr) +{ + 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 +expand-ptr-from-address yes +address /a.com/10.11.12.13 +address /a.com/64:ff9b::1010:1010 +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("13.12.11.10.in-addr.arpa PTR", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "13.12.11.10.in-addr.arpa"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "PTR"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "a.com."); + + ASSERT_TRUE(client.Query("0.1.0.1.0.1.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.9.f.f.4.6.0.0.ip6.arpa PTR", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), + "0.1.0.1.0.1.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.9.f.f.4.6.0.0.ip6.arpa"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "PTR"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "a.com."); +} + +TEST_F(Ptr, smartdns) +{ + 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"); + return smartdns::SERVER_REQUEST_OK; + } + + if (request->qtype == DNS_T_PTR) { + dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname"); + request->response_packet->head.rcode = DNS_RC_NOERROR; + return smartdns::SERVER_REQUEST_OK; + } + + return smartdns::SERVER_REQUEST_SOA; + }); + + server.Start(R"""(bind [::]:60053 +server 127.0.0.1:61053 +server-name my-server +log-num 0 +log-console yes +dualstack-ip-selection no +log-level debug +cache-persist no)"""); + smartdns::Client client; + ASSERT_TRUE(client.Query("1.0.0.127.in-addr.arpa PTR", 60053)); + std::cout << client.GetResult() << std::endl; + ASSERT_EQ(client.GetAnswerNum(), 1); + EXPECT_EQ(client.GetStatus(), "NOERROR"); + EXPECT_EQ(client.GetAnswer()[0].GetName(), "1.0.0.127.in-addr.arpa"); + EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600); + EXPECT_EQ(client.GetAnswer()[0].GetType(), "PTR"); + EXPECT_EQ(client.GetAnswer()[0].GetData(), "my-server."); +} diff --git a/test/server.cc b/test/server.cc index af1829c..880eb09 100644 --- a/test/server.cc +++ b/test/server.cc @@ -243,6 +243,7 @@ bool MockServer::Start(const std::string &url, ServerRequest callback) int port; char c_path[256]; int fd; + int yes = 1; struct sockaddr_storage addr; socklen_t addrlen; @@ -271,6 +272,9 @@ bool MockServer::Start(const std::string &url, ServerRequest callback) return false; } + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)); + if (bind(fd, (struct sockaddr *)&addr, addrlen) != 0) { close(fd); return false;