12
12
#include " test/integration/http_integration.h"
13
13
#include " test/integration/ssl_utility.h"
14
14
#include " test/test_common/registry.h"
15
+ #include " test/test_common/threadsafe_singleton_injector.h"
15
16
16
17
using testing::HasSubstr;
17
18
18
19
namespace Envoy {
19
20
namespace {
20
21
22
+ class OsSysCallsWithMockedDns : public Api ::OsSysCallsImpl {
23
+ public:
24
+ static addrinfo* makeAddrInfo (const Network::Address::InstanceConstSharedPtr& addr) {
25
+ addrinfo* ai = reinterpret_cast <addrinfo*>(malloc (sizeof (addrinfo)));
26
+ memset (ai, 0 , sizeof (addrinfo));
27
+ ai->ai_protocol = IPPROTO_TCP;
28
+ ai->ai_socktype = SOCK_STREAM;
29
+ if (addr->ip ()->ipv4 () != nullptr ) {
30
+ ai->ai_family = AF_INET;
31
+ } else {
32
+ ai->ai_family = AF_INET6;
33
+ }
34
+ sockaddr_storage* storage =
35
+ reinterpret_cast <sockaddr_storage*>(malloc (sizeof (sockaddr_storage)));
36
+ ai->ai_addr = reinterpret_cast <sockaddr*>(storage);
37
+ memcpy (ai->ai_addr , addr->sockAddr (), addr->sockAddrLen ());
38
+ ai->ai_addrlen = addr->sockAddrLen ();
39
+ return ai;
40
+ }
41
+
42
+ Api::SysCallIntResult getaddrinfo (const char * node, const char * /* service*/ ,
43
+ const addrinfo* /* hints*/ , addrinfo** res) override {
44
+ *res = nullptr ;
45
+ if (absl::string_view{" localhost" } == node) {
46
+ if (ip_version_ == Network::Address::IpVersion::v6) {
47
+ *res = makeAddrInfo (Network::Utility::getIpv6LoopbackAddress ());
48
+ } else {
49
+ *res = makeAddrInfo (Network::Utility::getCanonicalIpv4LoopbackAddress ());
50
+ }
51
+ return {0 , 0 };
52
+ }
53
+ if (nonexisting_addresses_.find (node) != nonexisting_addresses_.end ()) {
54
+ return {EAI_NONAME, 0 };
55
+ }
56
+ std::cerr << " Mock DNS does not have entry for: " << node << std::endl;
57
+ return {-1 , 128 };
58
+ }
59
+ void freeaddrinfo (addrinfo* ai) override {
60
+ while (ai != nullptr ) {
61
+ addrinfo* p = ai;
62
+ ai = ai->ai_next ;
63
+ free (p->ai_addr );
64
+ free (p);
65
+ }
66
+ }
67
+
68
+ void setIpVersion (Network::Address::IpVersion version) { ip_version_ = version; }
69
+
70
+ Network::Address::IpVersion ip_version_ = Network::Address::IpVersion::v4;
71
+
72
+ absl::flat_hash_set<absl::string_view> nonexisting_addresses_ = {" doesnotexist.example.com" ,
73
+ " itdoesnotexist" };
74
+ };
75
+
21
76
class ProxyFilterIntegrationTest : public testing ::TestWithParam<Network::Address::IpVersion>,
22
77
public HttpIntegrationTest {
23
78
public:
24
79
ProxyFilterIntegrationTest () : HttpIntegrationTest(Http::CodecType::HTTP1, GetParam()) {
80
+ mock_os_sys_calls_.setIpVersion (GetParam ());
25
81
upstream_tls_ = true ;
26
82
filename_ = TestEnvironment::temporaryPath (" dns_cache.txt" );
27
83
::unlink (filename_.c_str());
@@ -36,6 +92,14 @@ class ProxyFilterIntegrationTest : public testing::TestWithParam<Network::Addres
36
92
setUpstreamProtocol (Http::CodecType::HTTP1);
37
93
}
38
94
95
+ void TearDown () override {
96
+ // Shut down the server and upstreams before os_calls_ goes out of scope to avoid syscalls
97
+ // during its removal racing with the unlatching of the mocks.
98
+ test_server_.reset ();
99
+ cleanupUpstreamAndDownstream ();
100
+ fake_upstreams_.clear ();
101
+ }
102
+
39
103
void initialize () override { initializeWithArgs (); }
40
104
41
105
void initializeWithArgs (uint64_t max_hosts = 1024 , uint32_t max_pending_requests = 1024 ,
@@ -349,6 +413,8 @@ name: envoy.clusters.dynamic_forward_proxy
349
413
}
350
414
}
351
415
416
+ OsSysCallsWithMockedDns mock_os_sys_calls_;
417
+ TestThreadsafeSingletonInjector<Api::OsSysCallsImpl> os_calls_{&mock_os_sys_calls_};
352
418
bool upstream_tls_{};
353
419
bool low_stream_limits_{};
354
420
std::string upstream_cert_name_{" upstreamlocalhost" };
@@ -422,9 +488,8 @@ TEST_P(ProxyFilterIntegrationTest, MultiPortTest) {
422
488
requestWithBodyTest ();
423
489
424
490
// Create a second upstream, and send a request there.
425
- // The second upstream is autonomous where the first was not so we'll only get a 200-ok if we hit
426
- // the new port.
427
- // this regression tests https://github.com/envoyproxy/envoy/issues/27331
491
+ // The second upstream is autonomous where the first was not so we'll only get a 200-ok if we
492
+ // hit the new port. this regression tests https://github.com/envoyproxy/envoy/issues/27331
428
493
autonomous_upstream_ = true ;
429
494
createUpstream (Network::Test::getCanonicalLoopbackAddress (version_), upstreamConfig ());
430
495
default_request_headers_.setHost (
@@ -436,16 +501,6 @@ TEST_P(ProxyFilterIntegrationTest, MultiPortTest) {
436
501
437
502
// Do a sanity check using the getaddrinfo() resolver.
438
503
TEST_P (ProxyFilterIntegrationTest, RequestWithBodyGetAddrInfoResolver) {
439
- // getaddrinfo() does not reliably return v6 addresses depending on the environment. For now
440
- // just run this on v4 which is most likely to succeed. In v6 only environments this test won't
441
- // run at all but should still be covered in public CI.
442
- if (GetParam () != Network::Address::IpVersion::v4) {
443
- return ;
444
- }
445
-
446
- // See https://github.com/envoyproxy/envoy/issues/28504.
447
- DISABLE_UNDER_WINDOWS;
448
-
449
504
requestWithBodyTest (R"EOF(
450
505
typed_dns_resolver_config:
451
506
name: envoy.network.dns_resolver.getaddrinfo
@@ -877,7 +932,8 @@ TEST_P(ProxyFilterIntegrationTest, UpstreamCleartext) {
877
932
checkSimpleRequestSuccess (0 , 0 , response.get ());
878
933
}
879
934
880
- // Regression test a bug where the host header was used for cache lookups rather than host:port key
935
+ // Regression test a bug where the host header was used for cache lookups rather than host:port
936
+ // key
881
937
TEST_P (ProxyFilterIntegrationTest, CacheSansPort) {
882
938
useAccessLog (" %RESPONSE_CODE_DETAILS%" );
883
939
initializeWithArgs ();
0 commit comments