1
#include <gmock/gmock-actions.h>
2
#include <gmock/gmock-spec-builders.h>
3
#include <gtest/gtest.h>
4
#include <spdlog/common.h>
5

            
6
#include <cstdint>
7
#include <list>
8
#include <memory>
9
#include <string>
10
#include <utility>
11
#include <vector>
12

            
13
#include "envoy/api/api.h"
14
#include "envoy/common/exception.h"
15
#include "envoy/filesystem/watcher.h"
16
#include "envoy/init/target.h"
17
#include "envoy/init/watcher.h"
18
#include "envoy/network/address.h"
19
#include "envoy/network/socket.h"
20

            
21
#include "source/common/common/base_logger.h"
22
#include "source/common/common/logger.h"
23
#include "source/common/common/statusor.h"
24
#include "source/common/init/watcher_impl.h"
25
#include "source/common/network/address_impl.h"
26
#include "source/common/network/socket_impl.h"
27
#include "source/common/stats/isolated_store_impl.h"
28

            
29
#include "test/mocks/filesystem/mocks.h"
30
#include "test/mocks/network/connection.h"
31
#include "test/mocks/network/io_handle.h"
32
#include "test/mocks/network/mocks.h"
33
#include "test/mocks/server/listener_factory_context.h"
34
#include "test/mocks/server/server_factory_context.h"
35
#include "test/test_common/utility.h"
36

            
37
#include "absl/status/status.h"
38
#include "absl/strings/string_view.h"
39
#include "cilium/accesslog.h"
40
#include "cilium/api/bpf_metadata.pb.h"
41
#include "cilium/bpf_metadata.h"
42
#include "gtest/gtest.h"
43
#include "tests/bpf_metadata.h"
44

            
45
using testing::Mock;
46
using testing::NiceMock;
47
using testing::ReturnRef;
48

            
49
namespace Envoy {
50
namespace Cilium {
51
namespace {
52

            
53
// Test Cilium::BpfMetadata::Config filter config
54
// (NOT Cilium::BpfMetadata::TestConfig)
55

            
56
class MetadataConfigTest : public testing::Test {
57
protected:
58
16
  MetadataConfigTest() : api_(Api::createApiForTest()) {
59
1056
    for (Logger::Logger& logger : Logger::Registry::loggers()) {
60
1056
      logger.setLevel(spdlog::level::trace);
61
1056
    }
62

            
63
16
    ON_CALL(context_.server_factory_context_, api()).WillByDefault(testing::ReturnRef(*api_));
64

            
65
16
    ON_CALL(context_.server_factory_context_.dispatcher_, createFilesystemWatcher_())
66
32
        .WillByDefault(Invoke([]() -> Filesystem::Watcher* {
67
32
          auto watcher = new Filesystem::MockWatcher();
68
32
          EXPECT_CALL(*watcher, addWatch(_, Filesystem::Watcher::Events::MovedTo, _))
69
32
              .WillOnce(Invoke([](absl::string_view, uint32_t, Filesystem::Watcher::OnChangedCb) {
70
32
                return absl::OkStatus();
71
32
              }));
72
32
          Mock::AllowLeak(watcher);
73
32
          return watcher;
74
32
        }));
75
16
    ON_CALL(context_.init_manager_, add(_))
76
16
        .WillByDefault(Invoke([this](const Init::Target& target) {
77
16
          target_handles_.push_back(target.createHandle("test"));
78
16
        }));
79
16
    ON_CALL(context_.init_manager_, initialize(_))
80
16
        .WillByDefault(Invoke([this](const Init::Watcher& watcher) {
81
16
          for (auto& handle : target_handles_) {
82
16
            handle->initialize(watcher);
83
16
          }
84
16
        }));
85

            
86
16
    options_ = std::make_shared<std::vector<Network::Socket::OptionConstSharedPtr>>();
87
16
    ON_CALL(socket_, options()).WillByDefault(ReturnRef(options_));
88
16
    ON_CALL(socket_, addOption_(_))
89
16
        .WillByDefault(Invoke([this](const Network::Socket::OptionConstSharedPtr& option) {
90
          options_->emplace_back(std::move(option));
91
        }));
92
16
    ON_CALL(socket_, addOptions_(_))
93
16
        .WillByDefault(Invoke([this](const Network::Socket::OptionsSharedPtr& options) {
94
          Network::Socket::appendOptions(options_, options);
95
        }));
96
16
    ON_CALL(socket_, ioHandle()).WillByDefault(ReturnRef(io_handle_));
97
16
    ON_CALL(testing::Const(socket_), ioHandle()).WillByDefault(ReturnRef(io_handle_));
98

            
99
    // Set up the original destination address.
100
    // - for egress this the destination pod address
101
    // - for ingress this is the pod IP
102
    // - port is a "well-known" "service" port
103
16
    original_dst_address = std::make_shared<Network::Address::Ipv4Instance>("10.2.2.2", 80);
104
16
    EXPECT_TRUE(original_dst_address);
105
16
    EXPECT_NE(nullptr, original_dst_address->ip());
106
16
    const auto original_dst_address_status =
107
16
        StatusOr<Network::Address::InstanceConstSharedPtr>(original_dst_address);
108
    // Set up the default local address.
109
    // This is the "tproxy" address the listener is listening on:
110
    // - IP is localhost
111
    // - port is allocated from the ephemeral range
112
16
    local_address_ = std::make_shared<Network::Address::Ipv4Instance>("127.0.0.1", 23456);
113
16
    EXPECT_TRUE(local_address_);
114
16
    EXPECT_NE(nullptr, local_address_->ip());
115

            
116
    // Set up the remote address.
117
    // - for egress this the pod IP
118
    // - for ingress this is the original source address
119
    // - port is from the ephemeral range
120
16
    remote_address_ = std::make_shared<Network::Address::Ipv4Instance>("10.1.1.1", 41234);
121
16
    EXPECT_TRUE(remote_address_);
122
16
    EXPECT_NE(nullptr, remote_address_->ip());
123

            
124
16
    ON_CALL(io_handle_, localAddress()).WillByDefault(testing::Return(original_dst_address_status));
125
16
    EXPECT_EQ(&io_handle_, &socket_.ioHandle());
126
16
    const auto addr = THROW_OR_RETURN_VALUE(socket_.ioHandle().localAddress(),
127
16
                                            Network::Address::InstanceConstSharedPtr)
128
16
                          .get();
129
16
    EXPECT_NE(nullptr, addr);
130
16
  }
131
16
  ~MetadataConfigTest() override {
132
16
    hostmap.reset();
133
16
    npmap.reset();
134
16
  }
135

            
136
16
  void SetUp() override {
137
    // Set up default host map
138
16
    host_map_config = R"EOF(version_info: "1"
139
16
resources:
140
16
- "@type": type.googleapis.com/cilium.NetworkPolicyHosts
141
16
  policy: 111
142
16
  host_addresses: [ "10.1.1.1", "f00d::1:1:1" ]
143
16
- "@type": type.googleapis.com/cilium.NetworkPolicyHosts
144
16
  policy: 222
145
16
  host_addresses: [ "10.2.2.2", "f00d::2:2:2" ]
146
16
- "@type": type.googleapis.com/cilium.NetworkPolicyHosts
147
16
  policy: 1
148
16
  host_addresses: [ "127.0.0.0/8", "::1/128" ]
149
16
- "@type": type.googleapis.com/cilium.NetworkPolicyHosts
150
16
  policy: 8
151
16
  host_addresses: [ "10.1.1.42", "face::42" ]
152
16
- "@type": type.googleapis.com/cilium.NetworkPolicyHosts
153
16
  policy: 12345678
154
16
  host_addresses: [ "192.168.1.0/24" ]
155
16
)EOF";
156

            
157
    // Set up default policy
158
16
    policy_config = R"EOF(version_info: "1"
159
16
resources:
160
16
- "@type": type.googleapis.com/cilium.NetworkPolicy
161
16
  endpoint_ips:
162
16
  - '10.1.1.1'
163
16
  - 'face::1:1:1'
164
16
  endpoint_id: 2048
165
16
  egress_per_port_policies:
166
16
  - port: 80
167
16
    rules:
168
16
    - remote_policies: [ 222 ]
169
16
- "@type": type.googleapis.com/cilium.NetworkPolicy
170
16
  endpoint_ips:
171
16
  - '10.2.2.2'
172
16
  - 'face::2:2:2'
173
16
  endpoint_id: 4096
174
16
  ingress_per_port_policies:
175
16
  - port: 80
176
16
    rules:
177
16
    - remote_policies: [ 111 ]
178
16
- "@type": type.googleapis.com/cilium.NetworkPolicy
179
16
  endpoint_ips:
180
16
  - '10.1.1.42'
181
16
  - 'face::42'
182
16
  endpoint_id: 42
183
16
  ingress_per_port_policies:
184
16
  - port: 0
185
16
    rules:
186
16
    - remote_policies: [ 9999, 12345678 ]
187
16
  egress_per_port_policies:
188
16
  - port: 0
189
16
    rules:
190
16
    - remote_policies: [ 222, 9999, 12345678 ]
191
16
)EOF";
192
16
  }
193

            
194
  void initialize(const ::cilium::BpfMetadata& config, std::string extra_host_map_config = "",
195
16
                  std::string extra_policy_config = "") {
196
16
    socket_.connection_info_provider_ =
197
16
        std::make_shared<Network::ConnectionInfoSetterImpl>(local_address_, remote_address_);
198

            
199
16
    host_map_config += extra_host_map_config;
200
16
    policy_config += extra_policy_config;
201

            
202
16
    initTestMaps(context_);
203

            
204
16
    Init::WatcherImpl watcher("metadata test", []() {});
205
16
    context_.initManager().initialize(watcher);
206

            
207
16
    config_ = std::make_shared<Cilium::BpfMetadata::Config>(config, context_);
208
16
    config_->hosts_ = hostmap;
209
16
    config_->npmap_ = npmap;
210
16
  }
211

            
212
16
  void TearDown() override {}
213

            
214
  Api::ApiPtr api_;
215
  Stats::IsolatedStoreImpl stats_;
216
  NiceMock<Server::Configuration::MockTransportSocketFactoryContext>
217
      transport_socket_factory_context_;
218
  NiceMock<Server::Configuration::MockListenerFactoryContext> context_;
219
  std::shared_ptr<Cilium::BpfMetadata::Config> config_;
220
  Network::Address::InstanceConstSharedPtr local_address_;
221
  Network::Address::InstanceConstSharedPtr remote_address_;
222
  NiceMock<Network::MockConnection> conn_;
223
  NiceMock<Network::MockConnectionSocket> socket_;
224
  NiceMock<Network::MockIoHandle> io_handle_;
225
  Network::Socket::OptionsSharedPtr options_;
226
  std::list<Init::TargetHandlePtr> target_handles_;
227
};
228

            
229
1
TEST_F(MetadataConfigTest, EmptyConfig) {
230
1
  ::cilium::BpfMetadata config{};
231

            
232
1
  EXPECT_NO_THROW(initialize(config));
233
1
}
234

            
235
1
TEST_F(MetadataConfigTest, InvalidL7lbConfig) {
236
1
  ::cilium::BpfMetadata config{};
237
1
  config.set_is_ingress(true);
238
1
  config.set_is_l7lb(true);
239

            
240
1
  EXPECT_THROW_WITH_MESSAGE(initialize(config), EnvoyException,
241
1
                            "cilium.bpf_metadata: is_l7lb may not be set with is_ingress");
242
1
}
243

            
244
1
TEST_F(MetadataConfigTest, InvalidIngressIpv4Address) {
245
1
  ::cilium::BpfMetadata config{};
246
1
  config.set_ipv4_source_address("invalid");
247

            
248
1
  EXPECT_THROW_WITH_MESSAGE(
249
1
      initialize(config), EnvoyException,
250
1
      "cilium.bpf_metadata: ipv4_source_address is not an IPv4 address: invalid");
251
1
}
252

            
253
1
TEST_F(MetadataConfigTest, InvalidIngressIpv6Address) {
254
1
  ::cilium::BpfMetadata config{};
255
1
  config.set_ipv6_source_address("invalid");
256

            
257
1
  EXPECT_THROW_WITH_MESSAGE(
258
1
      initialize(config), EnvoyException,
259
1
      "cilium.bpf_metadata: ipv6_source_address is not an IPv6 address: invalid");
260
1
}
261

            
262
1
TEST_F(MetadataConfigTest, EastWestL7LbConfig) {
263
1
  ::cilium::BpfMetadata config{};
264
1
  config.set_use_original_source_address(true);
265
1
  config.set_is_l7lb(true);
266
1
  config.set_ipv4_source_address("127.0.0.1");
267
1
  config.set_ipv6_source_address("::1");
268

            
269
1
  EXPECT_NO_THROW(initialize(config));
270
1
}
271

            
272
1
TEST_F(MetadataConfigTest, NorthSouthL7LbConfig) {
273
1
  ::cilium::BpfMetadata config{};
274
1
  config.set_is_l7lb(true);
275
1
  config.set_ipv4_source_address("127.0.0.1");
276
1
  config.set_ipv6_source_address("::1");
277

            
278
1
  EXPECT_NO_THROW(initialize(config));
279
1
}
280

            
281
// LEGACY N/S without policy enforcement
282
1
TEST_F(MetadataConfigTest, NorthSouthL7LbMetadata) {
283
  // Use external remote address
284
1
  remote_address_ = std::make_shared<Network::Address::Ipv4Instance>("192.168.1.1", 12345);
285

            
286
1
  ::cilium::BpfMetadata config{};
287
1
  config.set_is_l7lb(true);
288
1
  config.set_ipv4_source_address("10.1.1.42");
289
1
  config.set_ipv6_source_address("face::42");
290

            
291
1
  EXPECT_NO_THROW(initialize(config));
292

            
293
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
294
1
  EXPECT_TRUE(socket_metadata);
295

            
296
1
  auto policy_fs = socket_metadata->buildCiliumPolicyFilterState();
297
1
  EXPECT_NE(nullptr, policy_fs);
298

            
299
1
  EXPECT_EQ(8, policy_fs->source_identity_);
300
1
  EXPECT_EQ(false, policy_fs->ingress_);
301
1
  EXPECT_EQ(true, policy_fs->is_l7lb_);
302
1
  EXPECT_EQ(80, policy_fs->port_);
303
1
  EXPECT_EQ("", policy_fs->pod_ip_);
304
1
  EXPECT_EQ("", policy_fs->ingress_policy_name_);
305
1
  EXPECT_EQ(0, policy_fs->ingress_source_identity_);
306

            
307
1
  auto source_addresses_socket_option = socket_metadata->buildSourceAddressSocketOption(-1);
308
1
  EXPECT_NE(nullptr, source_addresses_socket_option);
309
1
  EXPECT_EQ(-1, source_addresses_socket_option->linger_time_);
310

            
311
1
  EXPECT_EQ(nullptr, source_addresses_socket_option->original_source_address_);
312
1
  EXPECT_EQ("10.1.1.42:0", source_addresses_socket_option->ipv4_source_address_->asString());
313
1
  EXPECT_EQ("[face::42]:0", source_addresses_socket_option->ipv6_source_address_->asString());
314

            
315
1
  auto cilium_mark_socket_option = socket_metadata->buildCiliumMarkSocketOption();
316
1
  EXPECT_NE(nullptr, cilium_mark_socket_option);
317

            
318
  // Check that Ingress security ID is used in the socket mark
319
1
  EXPECT_TRUE((cilium_mark_socket_option->mark_ & 0xffff) == 0x0B00 &&
320
1
              (cilium_mark_socket_option->mark_ >> 16) == 8);
321
1
}
322

            
323
1
TEST_F(MetadataConfigTest, NorthSouthL7LbIngressEnforcedMetadata) {
324
  // Use external remote address
325
1
  remote_address_ = std::make_shared<Network::Address::Ipv4Instance>("192.168.1.1", 12345);
326

            
327
1
  ::cilium::BpfMetadata config{};
328
1
  config.set_is_l7lb(true);
329
1
  config.set_ipv4_source_address("10.1.1.42");
330
1
  config.set_ipv6_source_address("face::42");
331
1
  config.set_enforce_policy_on_l7lb(true);
332
1
  EXPECT_NO_THROW(initialize(config));
333

            
334
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
335
1
  EXPECT_TRUE(socket_metadata);
336

            
337
1
  auto policy_fs = socket_metadata->buildCiliumPolicyFilterState();
338
1
  EXPECT_NE(nullptr, policy_fs);
339

            
340
1
  EXPECT_EQ(8, policy_fs->source_identity_);
341
1
  EXPECT_EQ(false, policy_fs->ingress_);
342
1
  EXPECT_EQ(true, policy_fs->is_l7lb_);
343
1
  EXPECT_EQ(80, policy_fs->port_);
344
1
  EXPECT_EQ("", policy_fs->pod_ip_);
345
1
  EXPECT_EQ("10.1.1.42", policy_fs->ingress_policy_name_);
346
1
  EXPECT_EQ(12345678, policy_fs->ingress_source_identity_);
347

            
348
1
  AccessLog::Entry log_entry;
349
1
  log_entry.entry_.set_policy_name("pod");
350

            
351
  // Expect policy accepts security ID 12345678 on ingress on port 80
352
1
  bool use_proxy_lib;
353
1
  std::string l7_proto;
354
1
  EXPECT_TRUE(
355
1
      policy_fs->enforceNetworkPolicy(conn_, 12345678, 80, "", use_proxy_lib, l7_proto, log_entry));
356
1
  EXPECT_FALSE(use_proxy_lib);
357
1
  EXPECT_EQ("", l7_proto);
358
1
  EXPECT_NE("pod", log_entry.entry_.policy_name());
359

            
360
1
  auto source_addresses_socket_option = socket_metadata->buildSourceAddressSocketOption(-1);
361
1
  EXPECT_NE(nullptr, source_addresses_socket_option);
362
1
  EXPECT_EQ(-1, source_addresses_socket_option->linger_time_);
363

            
364
1
  EXPECT_EQ(nullptr, source_addresses_socket_option->original_source_address_);
365
1
  EXPECT_EQ("10.1.1.42:0", source_addresses_socket_option->ipv4_source_address_->asString());
366
1
  EXPECT_EQ("[face::42]:0", source_addresses_socket_option->ipv6_source_address_->asString());
367

            
368
1
  auto cilium_mark_socket_option = socket_metadata->buildCiliumMarkSocketOption();
369
1
  EXPECT_NE(nullptr, cilium_mark_socket_option);
370

            
371
  // Check that Ingress security ID is used in the socket mark
372
1
  EXPECT_TRUE((cilium_mark_socket_option->mark_ & 0xffff) == 0x0B00 &&
373
1
              (cilium_mark_socket_option->mark_ >> 16) == 8);
374
1
}
375

            
376
1
TEST_F(MetadataConfigTest, NorthSouthL7LbPodAndIngressEnforcedMetadata) {
377
  // Use external remote address
378
1
  remote_address_ = std::make_shared<Network::Address::Ipv4Instance>("192.168.1.1", 12345);
379

            
380
1
  ::cilium::BpfMetadata config{};
381
1
  config.set_is_l7lb(true);
382
1
  config.set_ipv4_source_address("10.1.1.42");
383
1
  config.set_ipv6_source_address("face::42");
384
1
  config.set_enforce_policy_on_l7lb(true);
385

            
386
1
  std::string extra_host_map_config = R"EOF(- "@type": type.googleapis.com/cilium.NetworkPolicyHosts
387
1
  policy: 9999
388
1
  host_addresses: [ "192.168.1.1" ]
389
1
)EOF";
390

            
391
1
  std::string extra_policy_config = R"EOF(- "@type": type.googleapis.com/cilium.NetworkPolicy
392
1
  endpoint_ips:
393
1
  - '192.168.1.1'
394
1
  - 'face:192:168:1:1'
395
1
  endpoint_id: 3000
396
1
  egress_per_port_policies:
397
1
  - port: 80
398
1
    rules:
399
1
    - remote_policies: [ 222, 333 ]
400
1
)EOF";
401

            
402
1
  EXPECT_NO_THROW(initialize(config, extra_host_map_config, extra_policy_config));
403

            
404
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
405
1
  EXPECT_TRUE(socket_metadata);
406

            
407
1
  auto policy_fs = socket_metadata->buildCiliumPolicyFilterState();
408
1
  EXPECT_NE(nullptr, policy_fs);
409

            
410
1
  EXPECT_EQ(8, policy_fs->source_identity_);
411
1
  EXPECT_EQ(false, policy_fs->ingress_);
412
1
  EXPECT_EQ(true, policy_fs->is_l7lb_);
413
1
  EXPECT_EQ(80, policy_fs->port_);
414
1
  EXPECT_EQ("192.168.1.1", policy_fs->pod_ip_);
415
1
  EXPECT_EQ("10.1.1.42", policy_fs->ingress_policy_name_);
416
1
  EXPECT_EQ(9999, policy_fs->ingress_source_identity_);
417

            
418
1
  AccessLog::Entry log_entry;
419
1
  log_entry.entry_.set_policy_name("pod");
420

            
421
  // Expect pod policy denies security ID 12345678 on port 80 (only 222 allowed)
422
1
  bool use_proxy_lib;
423
1
  std::string l7_proto;
424
1
  EXPECT_FALSE(
425
1
      policy_fs->enforceNetworkPolicy(conn_, 12345678, 80, "", use_proxy_lib, l7_proto, log_entry));
426
1
  EXPECT_FALSE(use_proxy_lib);
427
1
  EXPECT_EQ("", l7_proto);
428
1
  EXPECT_EQ("pod", log_entry.entry_.policy_name());
429

            
430
  // Expect pod policy allows egress to security ID 222 on port 80
431
  // Ingress policy allows ingress from 9999 (pod's security ID)
432
  // Ingress policy allows 222 egress
433
1
  EXPECT_TRUE(
434
1
      policy_fs->enforceNetworkPolicy(conn_, 222, 80, "", use_proxy_lib, l7_proto, log_entry));
435
1
  EXPECT_FALSE(use_proxy_lib);
436
1
  EXPECT_EQ("", l7_proto);
437
1
  EXPECT_NE("pod", log_entry.entry_.policy_name());
438

            
439
  // Expect pod policy allows egress to security ID 333 on port 80
440
  // Ingress policy allows ingress from 9999
441
  // Ingress policy denies 333 egress
442
1
  EXPECT_FALSE(
443
1
      policy_fs->enforceNetworkPolicy(conn_, 333, 80, "", use_proxy_lib, l7_proto, log_entry));
444
1
  EXPECT_FALSE(use_proxy_lib);
445
1
  EXPECT_EQ("", l7_proto);
446
1
  EXPECT_NE("pod", log_entry.entry_.policy_name());
447

            
448
1
  auto source_addresses_socket_option = socket_metadata->buildSourceAddressSocketOption(-1);
449
1
  EXPECT_NE(nullptr, source_addresses_socket_option);
450
1
  EXPECT_EQ(-1, source_addresses_socket_option->linger_time_);
451

            
452
1
  EXPECT_EQ(nullptr, source_addresses_socket_option->original_source_address_);
453
1
  EXPECT_EQ("10.1.1.42:0", source_addresses_socket_option->ipv4_source_address_->asString());
454
1
  EXPECT_EQ("[face::42]:0", source_addresses_socket_option->ipv6_source_address_->asString());
455

            
456
1
  auto cilium_mark_socket_option = socket_metadata->buildCiliumMarkSocketOption();
457
1
  EXPECT_NE(nullptr, cilium_mark_socket_option);
458

            
459
  // Check that Ingress security ID is used in the socket mark
460
1
  EXPECT_TRUE((cilium_mark_socket_option->mark_ & 0xffff) == 0x0B00 &&
461
1
              (cilium_mark_socket_option->mark_ >> 16) == 8);
462
1
}
463

            
464
1
TEST_F(MetadataConfigTest, NorthSouthL7LbIngressEnforcedCIDRMetadata) {
465
  // Use external remote address
466
1
  remote_address_ = std::make_shared<Network::Address::Ipv4Instance>("192.168.2.1", 12345);
467

            
468
1
  ::cilium::BpfMetadata config{};
469
1
  config.set_is_l7lb(true);
470
1
  config.set_ipv4_source_address("10.1.1.42");
471
1
  config.set_ipv6_source_address("face::42");
472
1
  config.set_enforce_policy_on_l7lb(true);
473
1
  EXPECT_NO_THROW(initialize(config));
474

            
475
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
476
1
  EXPECT_TRUE(socket_metadata);
477

            
478
1
  auto policy_fs = socket_metadata->buildCiliumPolicyFilterState();
479
1
  EXPECT_NE(nullptr, policy_fs);
480

            
481
1
  EXPECT_EQ(8, policy_fs->source_identity_);
482
1
  EXPECT_EQ(false, policy_fs->ingress_);
483
1
  EXPECT_EQ(true, policy_fs->is_l7lb_);
484
1
  EXPECT_EQ(80, policy_fs->port_);
485
1
  EXPECT_EQ("", policy_fs->pod_ip_);
486
1
  EXPECT_EQ("10.1.1.42", policy_fs->ingress_policy_name_);
487
1
  EXPECT_EQ(2, policy_fs->ingress_source_identity_);
488

            
489
1
  AccessLog::Entry log_entry;
490
1
  log_entry.entry_.set_policy_name("pod");
491

            
492
  // Expect policy does not accept security ID 2 on port 80
493
1
  bool use_proxy_lib;
494
1
  std::string l7_proto;
495
1
  EXPECT_FALSE(
496
1
      policy_fs->enforceNetworkPolicy(conn_, 2, 80, "", use_proxy_lib, l7_proto, log_entry));
497
1
  EXPECT_FALSE(use_proxy_lib);
498
1
  EXPECT_EQ("", l7_proto);
499
1
  EXPECT_NE("pod", log_entry.entry_.policy_name());
500

            
501
1
  auto source_addresses_socket_option = socket_metadata->buildSourceAddressSocketOption(-1);
502
1
  EXPECT_NE(nullptr, source_addresses_socket_option);
503
1
  EXPECT_EQ(-1, source_addresses_socket_option->linger_time_);
504

            
505
1
  EXPECT_EQ(nullptr, source_addresses_socket_option->original_source_address_);
506
1
  EXPECT_EQ("10.1.1.42:0", source_addresses_socket_option->ipv4_source_address_->asString());
507
1
  EXPECT_EQ("[face::42]:0", source_addresses_socket_option->ipv6_source_address_->asString());
508

            
509
1
  auto cilium_mark_socket_option = socket_metadata->buildCiliumMarkSocketOption();
510
1
  EXPECT_NE(nullptr, cilium_mark_socket_option);
511

            
512
  // Check that Ingress security ID is used in the socket mark
513
1
  EXPECT_TRUE((cilium_mark_socket_option->mark_ & 0xffff) == 0x0B00 &&
514
1
              (cilium_mark_socket_option->mark_ >> 16) == 8);
515
1
}
516

            
517
// Use external remote address, but config says to use original source address
518
1
TEST_F(MetadataConfigTest, ExternalUseOriginalSourceL7LbMetadata) {
519
1
  remote_address_ = std::make_shared<Network::Address::Ipv4Instance>("192.168.1.1", 12345);
520

            
521
1
  ::cilium::BpfMetadata config{};
522
1
  config.set_is_l7lb(true);
523
1
  config.set_use_original_source_address(true);
524
1
  config.set_ipv4_source_address("10.1.1.42");
525
1
  config.set_ipv6_source_address("face::42");
526

            
527
1
  EXPECT_NO_THROW(initialize(config));
528

            
529
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
530
1
  EXPECT_FALSE(socket_metadata);
531
1
}
532

            
533
1
TEST_F(MetadataConfigTest, EastWestL7LbMetadata) {
534
1
  ::cilium::BpfMetadata config{};
535
1
  config.set_use_original_source_address(true);
536
1
  config.set_is_l7lb(true);
537
1
  config.set_ipv4_source_address("10.1.1.42");
538
1
  config.set_ipv6_source_address("face::42");
539

            
540
1
  EXPECT_NO_THROW(initialize(config));
541

            
542
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
543
1
  EXPECT_TRUE(socket_metadata);
544

            
545
1
  auto policy_fs = socket_metadata->buildCiliumPolicyFilterState();
546
1
  EXPECT_NE(nullptr, policy_fs);
547

            
548
1
  EXPECT_EQ(111, policy_fs->source_identity_);
549
1
  EXPECT_EQ(false, policy_fs->ingress_);
550
1
  EXPECT_EQ(true, policy_fs->is_l7lb_);
551
1
  EXPECT_EQ(80, policy_fs->port_);
552
1
  EXPECT_EQ("10.1.1.1", policy_fs->pod_ip_);
553
1
  EXPECT_EQ("", policy_fs->ingress_policy_name_);
554

            
555
  // test with 1 second SO_LINGER option
556
1
  auto source_addresses_socket_option = socket_metadata->buildSourceAddressSocketOption(1);
557
1
  EXPECT_NE(nullptr, source_addresses_socket_option);
558
1
  EXPECT_EQ(1, source_addresses_socket_option->linger_time_);
559

            
560
1
  EXPECT_EQ("10.1.1.1:41234", source_addresses_socket_option->original_source_address_->asString());
561
1
  EXPECT_EQ("10.1.1.1:41234", source_addresses_socket_option->ipv4_source_address_->asString());
562
1
  EXPECT_EQ("[face::1:1:1]:41234",
563
1
            source_addresses_socket_option->ipv6_source_address_->asString());
564

            
565
1
  auto cilium_mark_socket_option = socket_metadata->buildCiliumMarkSocketOption();
566
1
  EXPECT_NE(nullptr, cilium_mark_socket_option);
567

            
568
  // Check that Endpoint's ID is used in the socket mark
569
1
  EXPECT_TRUE((cilium_mark_socket_option->mark_ & 0xffff) == 0x0900 &&
570
1
              (cilium_mark_socket_option->mark_ >> 16) == 2048);
571
1
}
572

            
573
// When original source is not configured to be used, east/west traffic takes the north/south path
574
// but retains local pod's IP as the "policy name" it found.
575
1
TEST_F(MetadataConfigTest, EastWestL7LbMetadataNoOriginalSource) {
576
1
  ::cilium::BpfMetadata config{};
577
1
  config.set_is_l7lb(true);
578
1
  config.set_ipv4_source_address("10.1.1.42");
579
1
  config.set_ipv6_source_address("face::42");
580

            
581
1
  EXPECT_NO_THROW(initialize(config));
582

            
583
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
584
1
  EXPECT_TRUE(socket_metadata);
585

            
586
1
  auto policy_fs = socket_metadata->buildCiliumPolicyFilterState();
587
1
  EXPECT_NE(nullptr, policy_fs);
588

            
589
1
  EXPECT_EQ(8, policy_fs->source_identity_);
590
1
  EXPECT_EQ(false, policy_fs->ingress_);
591
1
  EXPECT_EQ(true, policy_fs->is_l7lb_);
592
1
  EXPECT_EQ(80, policy_fs->port_);
593
1
  EXPECT_EQ("10.1.1.1", policy_fs->pod_ip_);
594
1
  EXPECT_EQ("", policy_fs->ingress_policy_name_);
595
1
  EXPECT_EQ(0, policy_fs->ingress_source_identity_);
596

            
597
1
  auto source_addresses_socket_option = socket_metadata->buildSourceAddressSocketOption(-1);
598
1
  EXPECT_NE(nullptr, source_addresses_socket_option);
599
1
  EXPECT_EQ(-1, source_addresses_socket_option->linger_time_);
600

            
601
1
  EXPECT_EQ(nullptr, source_addresses_socket_option->original_source_address_);
602
1
  EXPECT_EQ("10.1.1.42:0", source_addresses_socket_option->ipv4_source_address_->asString());
603
1
  EXPECT_EQ("[face::42]:0", source_addresses_socket_option->ipv6_source_address_->asString());
604

            
605
1
  auto cilium_mark_socket_option = socket_metadata->buildCiliumMarkSocketOption();
606
1
  EXPECT_NE(nullptr, cilium_mark_socket_option);
607

            
608
  // Check that Ingress ID is used in the socket mark
609
1
  EXPECT_TRUE((cilium_mark_socket_option->mark_ & 0xffff) == 0x0B00 &&
610
1
              (cilium_mark_socket_option->mark_ >> 16) == 8);
611
1
}
612

            
613
1
TEST_F(MetadataConfigTest, ProxyLibNotConfigured) {
614
1
  ::cilium::BpfMetadata config{};
615

            
616
1
  EXPECT_NO_THROW(initialize(config));
617

            
618
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
619
1
  EXPECT_TRUE(socket_metadata);
620

            
621
1
  EXPECT_CALL(socket_, setRequestedApplicationProtocols(_)).Times(0);
622

            
623
1
  socket_metadata->configureProxyLibApplicationProtocol(socket_);
624
1
}
625

            
626
1
TEST_F(MetadataConfigTest, ProxyLibConfigured) {
627
1
  ::cilium::BpfMetadata config{};
628

            
629
1
  EXPECT_NO_THROW(initialize(config));
630

            
631
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
632
1
  EXPECT_TRUE(socket_metadata);
633

            
634
  // set proxylib proto manually
635
1
  socket_metadata->proxylib_l7_proto_ = "r2d2";
636

            
637
1
  std::vector<std::string> protocols = {"h2c"};
638
1
  EXPECT_CALL(socket_, requestedApplicationProtocols).WillOnce(testing::ReturnRef(protocols));
639

            
640
  // proxylib protocol should be appended to the list of existing requested application protocols
641
1
  const auto protos = std::vector<absl::string_view>{"h2c", "r2d2"};
642
1
  EXPECT_CALL(socket_, setRequestedApplicationProtocols(protos));
643

            
644
1
  socket_metadata->configureProxyLibApplicationProtocol(socket_);
645
1
}
646

            
647
1
TEST_F(MetadataConfigTest, RestoreLocalAddress) {
648
1
  ::cilium::BpfMetadata config{};
649

            
650
1
  EXPECT_NO_THROW(initialize(config));
651

            
652
1
  auto socket_metadata = config_->extractSocketMetadata(socket_);
653
1
  EXPECT_TRUE(socket_metadata);
654

            
655
1
  EXPECT_NE(socket_.connectionInfoProvider().localAddress(), original_dst_address);
656
1
  EXPECT_FALSE(socket_.connectionInfoProvider().localAddressRestored());
657

            
658
1
  socket_metadata->configureOriginalDstAddress(socket_);
659

            
660
1
  EXPECT_EQ(socket_.connectionInfoProvider().localAddress(), original_dst_address);
661
1
  EXPECT_TRUE(socket_.connectionInfoProvider().localAddressRestored());
662
1
}
663

            
664
} // namespace
665
} // namespace Cilium
666
} // namespace Envoy