| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- #include "client.h"
- #include "server.h"
- #include "smartdns/dns.h"
- #include "smartdns/http2.h"
- #include "gtest/gtest.h"
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <thread>
- // Test HTTP/2 with bind-https server (simulating upstream HTTPS server)
- TEST(HTTP2, BindServerHTTP2)
- {
- Defer
- {
- unlink("/tmp/smartdns-cert.pem");
- unlink("/tmp/smartdns-key.pem");
- };
- smartdns::Server server_wrap;
- smartdns::Server server;
- // Start main SmartDNS instance that queries upstream HTTPS server
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn h2
- log-level debug
- )""");
- // Start upstream HTTPS server (bind-https)
- server_wrap.Start(R"""(bind-https [::]:60053 -alpn h2
- address /example.com/1.2.3.4
- address /test.com/5.6.7.8
- log-level debug
- )""");
- smartdns::Client client;
- // Test first query
- ASSERT_TRUE(client.Query("example.com", 61053));
- std::cout << client.GetResult() << std::endl;
- ASSERT_EQ(client.GetAnswerNum(), 1);
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
- // Test second query to verify connection reuse
- ASSERT_TRUE(client.Query("test.com", 61053));
- std::cout << client.GetResult() << std::endl;
- ASSERT_EQ(client.GetAnswerNum(), 1);
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
- }
- TEST(HTTP2, ServerMultiStream)
- {
- smartdns::Server server_wrap;
- smartdns::Server server;
- // Start main SmartDNS instance
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn h2
- log-level debug
- )""");
- // Start upstream HTTPS server (bind-https)
- server_wrap.Start(R"""(bind-https [::]:60053 -alpn h2
- address /example.com/1.2.3.4
- address /test.com/5.6.7.8
- log-level debug
- )""");
- smartdns::Client client;
-
- // Send multiple concurrent queries
- // Note: The smartdns::Client might be synchronous, so we might need threads or a way to send async.
- // But we can verify that multiple queries on the same connection work (multiplexing).
- // The previous test already verified connection reuse.
- // To verify concurrency, we'd need to delay the response on the server, which is hard with bind-https.
- // However, we can at least verify that sending many queries quickly works.
-
- for (int i = 0; i < 10; i++) {
- ASSERT_TRUE(client.Query("example.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
- }
- }
- TEST(HTTP2, ServerALPNConfig)
- {
- smartdns::Server server_wrap;
- smartdns::Server server;
- // Case 1: Server supports h2, client requests h2 -> h2
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn h2
- log-level debug
- )""");
- server_wrap.Start(R"""(bind-https [::]:60053 -alpn h2
- address /example.com/1.2.3.4
- log-level debug
- )""");
- smartdns::Client client;
- ASSERT_TRUE(client.Query("example.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- }
- TEST(HTTP2, ServerALPNFallback)
- {
- smartdns::Server server_wrap;
- smartdns::Server server;
- // Case 2: Server supports http/1.1 only, client requests h2 -> fallback or fail?
- // If client requests h2 only, it should fail.
- // If client requests h2,http/1.1, it should fallback.
-
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn h2,http/1.1
- log-level debug
- )""");
- server_wrap.Start(R"""(bind-https [::]:60053 -alpn http/1.1
- address /example.com/1.2.3.4
- log-level debug
- )""");
- smartdns::Client client;
- ASSERT_TRUE(client.Query("example.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- }
- // Test client only supports HTTP/1.1, server supports both
- TEST(HTTP2, ClientHTTP1Only)
- {
- smartdns::Server server_wrap;
- smartdns::Server server;
- // Client only supports http/1.1, server supports both h2 and http/1.1
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn http/1.1
- log-level debug
- )""");
- server_wrap.Start(R"""(bind-https [::]:60053 -alpn h2,http/1.1
- address /example.com/1.2.3.4
- log-level debug
- )""");
- smartdns::Client client;
- ASSERT_TRUE(client.Query("example.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
- }
- // Test both client and server only support HTTP/1.1
- TEST(HTTP2, BothHTTP1Only)
- {
- smartdns::Server server_wrap;
- smartdns::Server server;
- // Both client and server only support http/1.1
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn http/1.1
- log-level debug
- )""");
- server_wrap.Start(R"""(bind-https [::]:60053 -alpn http/1.1
- address /example.com/1.2.3.4
- address /test2.com/9.10.11.12
- log-level debug
- )""");
- smartdns::Client client;
-
- // First query
- ASSERT_TRUE(client.Query("example.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
-
- // Second query to verify connection reuse with HTTP/1.1
- ASSERT_TRUE(client.Query("test2.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "9.10.11.12");
- }
- // Test concurrent queries from multiple clients
- TEST(HTTP2, ConcurrentClients)
- {
- smartdns::Server server_wrap;
- smartdns::Server server;
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn h2
- log-level debug
- )""");
- server_wrap.Start(R"""(bind-https [::]:60053 -alpn h2
- address /example.com/1.2.3.4
- address /test.com/5.6.7.8
- log-level debug
- )""");
- // Create multiple threads to query simultaneously
- std::vector<std::thread> threads;
- std::atomic<int> success_count{0};
-
- for (int i = 0; i < 5; i++) {
- threads.emplace_back([&success_count, i]() {
- smartdns::Client client;
- const char* domain = (i % 2 == 0) ? "example.com" : "test.com";
- const char* expected_ip = (i % 2 == 0) ? "1.2.3.4" : "5.6.7.8";
-
- if (client.Query(domain, 61053)) {
- if (client.GetStatus() == "NOERROR" &&
- client.GetAnswerNum() > 0 &&
- client.GetAnswer()[0].GetData() == expected_ip) {
- success_count++;
- }
- }
- });
- }
-
- for (auto& t : threads) {
- t.join();
- }
-
- EXPECT_EQ(success_count.load(), 5);
- }
- // Test mixed HTTP/2 and HTTP/1.1 queries
- TEST(HTTP2, MixedProtocolQueries)
- {
- smartdns::Server server_wrap_h2;
- smartdns::Server server_wrap_http1;
- smartdns::Server server;
- // Main server supports both protocols
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn h2,http/1.1
- server https://127.0.0.1:60054/dns-query -no-check-certificate -alpn http/1.1
- log-level debug
- )""");
- // First upstream supports HTTP/2
- server_wrap_h2.Start(R"""(bind-https [::]:60053 -alpn h2
- address /h2-domain.com/1.1.1.1
- log-level debug
- )""");
- // Second upstream supports HTTP/1.1 only
- server_wrap_http1.Start(R"""(bind-https [::]:60054 -alpn http/1.1
- address /http1-domain.com/2.2.2.2
- log-level debug
- )""");
- smartdns::Client client;
-
- // Query from HTTP/2 server
- ASSERT_TRUE(client.Query("h2-domain.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.1.1.1");
-
- // Query from HTTP/1.1 server
- ASSERT_TRUE(client.Query("http1-domain.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "2.2.2.2");
- }
- // Test connection reuse for HTTP/2
- TEST(HTTP2, ConnectionReuse)
- {
- smartdns::Server server_wrap;
- smartdns::Server server;
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate -alpn h2
- log-level debug
- )""");
- server_wrap.Start(R"""(bind-https [::]:60053 -alpn h2
- address /domain1.com/1.1.1.1
- address /domain2.com/2.2.2.2
- address /domain3.com/3.3.3.3
- log-level debug
- )""");
- smartdns::Client client;
-
- // Multiple queries that should reuse the same HTTP/2 connection
- for (int i = 1; i <= 3; i++) {
- std::string domain = "domain" + std::to_string(i) + ".com";
- std::string expected_ip = std::to_string(i) + "." + std::to_string(i) + "." + std::to_string(i) + "." + std::to_string(i);
-
- ASSERT_TRUE(client.Query(domain.c_str(), 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), expected_ip);
- }
- }
- // Test default ALPN behavior (no explicit -alpn parameter)
- TEST(HTTP2, DefaultALPN)
- {
- smartdns::Server server_wrap;
- smartdns::Server server;
- // Client doesn't specify ALPN (should default to supporting both)
- server.Start(R"""(bind [::]:61053
- server https://127.0.0.1:60053/dns-query -no-check-certificate
- log-level debug
- )""");
- // Server supports both (no explicit -alpn, should default to h2,http/1.1)
- server_wrap.Start(R"""(bind-https [::]:60053
- address /example.com/1.2.3.4
- log-level debug
- )""");
- smartdns::Client client;
- ASSERT_TRUE(client.Query("example.com", 61053));
- EXPECT_EQ(client.GetStatus(), "NOERROR");
- EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
- }
|