diff --git a/collector/lib/CollectorConfig.cpp b/collector/lib/CollectorConfig.cpp index 54a434a5c1..810eba62aa 100644 --- a/collector/lib/CollectorConfig.cpp +++ b/collector/lib/CollectorConfig.cpp @@ -91,7 +91,6 @@ constexpr const char* CollectorConfig::kSyscalls[]; constexpr bool CollectorConfig::kEnableProcessesListeningOnPorts; const UnorderedSet CollectorConfig::kIgnoredL4ProtoPortPairs = {{L4Proto::UDP, 9}}; -; CollectorConfig::CollectorConfig() { // Set default configuration values @@ -439,7 +438,7 @@ std::ostream& operator<<(std::ostream& os, const CollectorConfig& c) { << ", set_import_users:" << c.ImportUsers() << ", collect_connection_status:" << c.CollectConnectionStatus() << ", enable_detailed_metrics:" << c.EnableDetailedMetrics() - << ", enable_external_ips:" << c.EnableExternalIPs() + << ", external_ips:" << c.ExternalIPsConf() << ", track_send_recv:" << c.TrackingSendRecv(); } diff --git a/collector/lib/CollectorConfig.h b/collector/lib/CollectorConfig.h index e62f658dad..90af256654 100644 --- a/collector/lib/CollectorConfig.h +++ b/collector/lib/CollectorConfig.h @@ -14,6 +14,7 @@ #include #include "CollectionMethod.h" +#include "ExternalIPsConfig.h" #include "HostConfig.h" #include "Logging.h" #include "NetworkConnection.h" @@ -97,15 +98,10 @@ class CollectorConfig { // EnableExternalIPs will check for the existence // of a runtime configuration, and defer to that value // otherwise, we rely on the feature flag (env var) - bool EnableExternalIPs() const { + ExternalIPsConfig ExternalIPsConf() const { auto lock = ReadLock(); - if (runtime_config_.has_value()) { - return runtime_config_.value() - .networking() - .external_ips() - .enabled() == sensor::ExternalIpsEnabled::ENABLED; - } - return enable_external_ips_; + + return ExternalIPsConfig(runtime_config_, enable_external_ips_); } void RuntimeConfigHeuristics() { diff --git a/collector/lib/ConnTracker.cpp b/collector/lib/ConnTracker.cpp index 9b21934417..0d3d469a7c 100644 --- a/collector/lib/ConnTracker.cpp +++ b/collector/lib/ConnTracker.cpp @@ -112,7 +112,7 @@ IPNet ConnectionTracker::NormalizeAddressNoLock(const Address& address, bool ena } bool ConnectionTracker::ShouldNormalizeConnection(const Connection* conn) const { - Endpoint local, remote = conn->remote(); + Endpoint remote = conn->remote(); IPNet ipnet = NormalizeAddressNoLock(remote.address(), false); return Address::IsCanonicalExternalIp(ipnet.address()); @@ -136,30 +136,31 @@ void ConnectionTracker::CloseConnections(ConnMap* old_conn_state, ConnMap* delta } } -/** - * Closes connections that have the 255.255.255.255 external IP address - */ -void ConnectionTracker::CloseNormalizedConnections(ConnMap* old_conn_state, ConnMap* delta_conn) { - CloseConnections(old_conn_state, delta_conn, [](const Connection* conn) { - return Address::IsCanonicalExternalIp(conn->remote().address()); - }); -} +void ConnectionTracker::CloseConnectionsOnExternalIPsConfigChange(ExternalIPsConfig prev_config, ConnMap* old_conn_state, ConnMap* delta_conn) const { + bool ingress = external_IPs_config_.IsEnabled(ExternalIPsConfig::Direction::INGRESS); + bool egress = external_IPs_config_.IsEnabled(ExternalIPsConfig::Direction::EGRESS); -/** - * Closes unnormalized connections that would be normalized to the canonical external - * IP address if external IPs was enabled - */ -void ConnectionTracker::CloseExternalUnnormalizedConnections(ConnMap* old_conn_state, ConnMap* delta_conn) { - CloseConnections(old_conn_state, delta_conn, [this](const Connection* conn) { - return ShouldNormalizeConnection(conn) && !Address::IsCanonicalExternalIp(conn->remote().address()); - }); -} + auto should_close = [this](const Connection* conn, bool enabling_extIPs) { + if (enabling_extIPs) { + // Enabling: Close connections previously normalized + return Address::IsCanonicalExternalIp(conn->remote().address()); + } else { + // Disabling: Close connections that should now be normalized + return !Address::IsCanonicalExternalIp(conn->remote().address()) && ShouldNormalizeConnection(conn); + } + }; -void ConnectionTracker::CloseConnectionsOnRuntimeConfigChange(ConnMap* old_conn_state, ConnMap* delta_conn, bool enableExternalIPs) { - if (enableExternalIPs) { - CloseNormalizedConnections(old_conn_state, delta_conn); - } else { - CloseExternalUnnormalizedConnections(old_conn_state, delta_conn); + if (egress != prev_config.IsEnabled(ExternalIPsConfig::Direction::EGRESS)) { + CloseConnections(old_conn_state, delta_conn, [egress, should_close](const Connection* conn) -> bool { + /* egress is when we are not server */ + return !conn->is_server() && should_close(conn, egress); + }); + } + if (ingress != prev_config.IsEnabled(ExternalIPsConfig::Direction::INGRESS)) { + CloseConnections(old_conn_state, delta_conn, [ingress, should_close](const Connection* conn) -> bool { + /* ingress is when we are server */ + return conn->is_server() && should_close(conn, ingress); + }); } } @@ -171,15 +172,17 @@ Connection ConnectionTracker::NormalizeConnectionNoLock(const Connection& conn) } Endpoint local, remote = conn.remote(); + bool extIPs_ingress = external_IPs_config_.IsEnabled(ExternalIPsConfig::Direction::INGRESS); + bool extIPs_egress = external_IPs_config_.IsEnabled(ExternalIPsConfig::Direction::EGRESS); if (is_server) { // If this is the server, only the local port is relevant, while the remote port does not matter. local = Endpoint(IPNet(Address()), conn.local().port()); - remote = Endpoint(NormalizeAddressNoLock(conn.remote().address(), enable_external_ips_), 0); + remote = Endpoint(NormalizeAddressNoLock(conn.remote().address(), extIPs_ingress), 0); } else { // If this is the client, the local port and address are not relevant. local = Endpoint(); - remote = Endpoint(NormalizeAddressNoLock(remote.address(), enable_external_ips_), remote.port()); + remote = Endpoint(NormalizeAddressNoLock(remote.address(), extIPs_egress), remote.port()); } return Connection(conn.container(), local, remote, conn.l4proto(), is_server); diff --git a/collector/lib/ConnTracker.h b/collector/lib/ConnTracker.h index d4fbe5fe1f..c86fa89205 100644 --- a/collector/lib/ConnTracker.h +++ b/collector/lib/ConnTracker.h @@ -4,6 +4,7 @@ #include #include "Containers.h" +#include "ExternalIPsConfig.h" #include "Hash.h" #include "NRadix.h" #include "NetworkConnection.h" @@ -100,10 +101,10 @@ class ConnectionTracker { template static void UpdateOldState(UnorderedMap* old_state, const UnorderedMap& new_state, int64_t time_micros, int64_t afterglow_period_micros); - void CloseConnections(ConnMap* old_conn_state, ConnMap* delta_conn, std::function predicate); - void CloseNormalizedConnections(ConnMap* old_conn_state, ConnMap* delta_conn); - void CloseExternalUnnormalizedConnections(ConnMap* old_conn_state, ConnMap* delta_conn); - void CloseConnectionsOnRuntimeConfigChange(ConnMap* old_conn_state, ConnMap* delta_conn, bool enableExternalIPs); + // Mark all matching connections as closed + static void CloseConnections(ConnMap* old_conn_state, ConnMap* delta_conn, std::function predicate); + // Detect a change in the External-IPs config and report connections as closed if their representation is affected + void CloseConnectionsOnExternalIPsConfigChange(ExternalIPsConfig prev_config, ConnMap* old_conn_state, ConnMap* delta_conn) const; // ComputeDelta computes a diff between new_state and old_state template @@ -131,7 +132,7 @@ class ConnectionTracker { void UpdateKnownPublicIPs(UnorderedSet
&& known_public_ips); void UpdateKnownIPNetworks(UnorderedMap>&& known_ip_networks); - void EnableExternalIPs(bool enable) { enable_external_ips_ = enable; } + void SetExternalIPsConfig(ExternalIPsConfig config) { external_IPs_config_ = config; } void UpdateIgnoredL4ProtoPortPairs(UnorderedSet&& ignored_l4proto_port_pairs); void UpdateIgnoredNetworks(const std::vector& network_list); void UpdateNonAggregatedNetworks(const std::vector& network_list); @@ -202,7 +203,7 @@ class ConnectionTracker { UnorderedSet
known_public_ips_; NRadixTree known_ip_networks_; - bool enable_external_ips_ = false; + ExternalIPsConfig external_IPs_config_; UnorderedMap known_private_networks_exists_; UnorderedSet ignored_l4proto_port_pairs_; NRadixTree ignored_networks_; diff --git a/collector/lib/ExternalIPsConfig.cpp b/collector/lib/ExternalIPsConfig.cpp new file mode 100644 index 0000000000..1d57ecda65 --- /dev/null +++ b/collector/lib/ExternalIPsConfig.cpp @@ -0,0 +1,55 @@ +#include "ExternalIPsConfig.h" + +namespace collector { + +ExternalIPsConfig::ExternalIPsConfig(std::optional runtime_config, bool default_enabled) { + if (!runtime_config.has_value()) { + direction_enabled_ = default_enabled ? Direction::BOTH : Direction::NONE; + return; + } + + // At this point we know runtime_config has a value, we can access it directly + const auto& external_ips = runtime_config->networking().external_ips(); + if (external_ips.enabled() != sensor::ExternalIpsEnabled::ENABLED) { + direction_enabled_ = Direction::NONE; + return; + } + + switch (external_ips.direction()) { + case sensor::ExternalIpsDirection::INGRESS: + direction_enabled_ = Direction::INGRESS; + break; + case sensor::ExternalIpsDirection::EGRESS: + direction_enabled_ = Direction::EGRESS; + break; + default: + direction_enabled_ = Direction::BOTH; + break; + } +} + +std::ostream& operator<<(std::ostream& os, const ExternalIPsConfig& config) { + os << "direction("; + + switch (config.GetDirection()) { + case ExternalIPsConfig::Direction::NONE: + os << "NONE"; + break; + case ExternalIPsConfig::Direction::INGRESS: + os << "INGRESS"; + break; + case ExternalIPsConfig::Direction::EGRESS: + os << "EGRESS"; + break; + case ExternalIPsConfig::Direction::BOTH: + os << "BOTH"; + break; + default: + os << "invalid"; + break; + } + + return os << ")"; +} + +} // namespace collector \ No newline at end of file diff --git a/collector/lib/ExternalIPsConfig.h b/collector/lib/ExternalIPsConfig.h new file mode 100644 index 0000000000..36737c63ec --- /dev/null +++ b/collector/lib/ExternalIPsConfig.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#include + +namespace collector { + +// Encapsulates the configuration of the External-IPs feature +class ExternalIPsConfig { + public: + enum Direction { + NONE = 1 << 2, + INGRESS = 1 << 0, + EGRESS = 1 << 1, + BOTH = INGRESS | EGRESS, + }; + + // Are External-IPs enabled in the provided direction ? + bool IsEnabled(Direction direction) const { return (direction & direction_enabled_) == direction; } + + // Direction in which External-IPs are enabled + Direction GetDirection() const { return direction_enabled_; } + + // Extract the External-IPs configuration from the provided runtime-conf. + // If the runtime-configuration is unset then 'default_enabled' is used + // as a fallback to enable in both directions. + // 'runtime_config' should be locked prior to calling. + ExternalIPsConfig(std::optional runtime_config, bool default_enabled); + + ExternalIPsConfig(Direction direction = Direction::NONE) : direction_enabled_(direction) {} + + private: + Direction direction_enabled_; +}; + +std::ostream& operator<<(std::ostream& os, const ExternalIPsConfig& config); + +} // end namespace collector diff --git a/collector/lib/NetworkStatusNotifier.cpp b/collector/lib/NetworkStatusNotifier.cpp index 8d37baf09a..abb25e4b5e 100644 --- a/collector/lib/NetworkStatusNotifier.cpp +++ b/collector/lib/NetworkStatusNotifier.cpp @@ -225,7 +225,7 @@ void NetworkStatusNotifier::RunSingle(IDuplexClientWriterSleep(next_scrape)) { CLOG(DEBUG) << "Starting network status notification"; @@ -242,18 +242,18 @@ void NetworkStatusNotifier::RunSingle(IDuplexClientWriterEnableExternalIPs(enableExternalIPs); + conn_tracker_->SetExternalIPsConfig(externalIPsConfig); new_conn_state = conn_tracker_->FetchConnState(true, true); if (config_.EnableAfterglow()) { ConnectionTracker::ComputeDeltaAfterglow(new_conn_state, old_conn_state, delta_conn, time_micros, time_at_last_scrape, config_.AfterglowPeriod()); - if (prevEnableExternalIPs != enableExternalIPs) { - conn_tracker_->CloseConnectionsOnRuntimeConfigChange(&old_conn_state, &delta_conn, enableExternalIPs); - prevEnableExternalIPs = enableExternalIPs; - } + + conn_tracker_->CloseConnectionsOnExternalIPsConfigChange(prevEnableExternalIPs, &old_conn_state, &delta_conn); + prevEnableExternalIPs = externalIPsConfig; + } else { ConnectionTracker::ComputeDelta(new_conn_state, &old_conn_state); } diff --git a/collector/proto/third_party/stackrox b/collector/proto/third_party/stackrox index 0e536c9e74..1d04bca326 160000 --- a/collector/proto/third_party/stackrox +++ b/collector/proto/third_party/stackrox @@ -1 +1 @@ -Subproject commit 0e536c9e7423aac43e1f79d8245ba52b311eef91 +Subproject commit 1d04bca3268f5edd3837a0850284be0fbd4100c3 diff --git a/collector/test/CollectorConfigTest.cpp b/collector/test/CollectorConfigTest.cpp index 8b03bb9af2..d4f8962d5b 100644 --- a/collector/test/CollectorConfigTest.cpp +++ b/collector/test/CollectorConfigTest.cpp @@ -4,10 +4,12 @@ #include "CollectorArgs.h" #include "CollectorConfig.h" +#include "ConfigLoader.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using namespace testing; +using Direction = collector::ExternalIPsConfig::Direction; namespace collector { @@ -115,11 +117,11 @@ TEST(CollectorConfigTest, TestEnableExternalIpsFeatureFlag) { config.MockSetEnableExternalIPs(false); - EXPECT_FALSE(config.EnableExternalIPs()); + EXPECT_EQ(Direction::NONE, config.ExternalIPsConf().GetDirection()); config.MockSetEnableExternalIPs(true); - EXPECT_TRUE(config.EnableExternalIPs()); + EXPECT_EQ(Direction::BOTH, config.ExternalIPsConf().GetDirection()); } TEST(CollectorConfigTest, TestEnableExternalIpsRuntimeConfig) { @@ -138,14 +140,111 @@ TEST(CollectorConfigTest, TestEnableExternalIpsRuntimeConfig) { config.SetRuntimeConfig(runtime_config); - EXPECT_FALSE(config.EnableExternalIPs()); + EXPECT_EQ(Direction::NONE, config.ExternalIPsConf().GetDirection()); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::INGRESS)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::EGRESS)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::BOTH)); config.MockSetEnableExternalIPs(false); external_ips_config->set_enabled(sensor::ExternalIpsEnabled::ENABLED); config.SetRuntimeConfig(runtime_config); - EXPECT_TRUE(config.EnableExternalIPs()); + EXPECT_EQ(Direction::BOTH, config.ExternalIPsConf().GetDirection()); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::INGRESS)); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::EGRESS)); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::BOTH)); +} + +TEST(CollectorConfigTest, TestIsEnabledIngress) { + std::string yamlStr = R"( + networking: + externalIps: + enabled: enabled + direction: ingress + )"; + + YAML::Node yamlNode = YAML::Load(yamlStr); + CollectorConfig config; + ASSERT_EQ(ConfigLoader(config).LoadConfiguration(yamlNode), ConfigLoader::SUCCESS) << "Input: " << yamlStr; + + auto runtime_config = config.GetRuntimeConfig(); + + EXPECT_TRUE(runtime_config.has_value()); + + EXPECT_EQ(Direction::INGRESS, config.ExternalIPsConf().GetDirection()); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::INGRESS)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::EGRESS)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::BOTH)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::NONE)); +} + +TEST(CollectorConfigTest, TestIsEnabledEgress) { + std::string yamlStr = R"( + networking: + externalIps: + enabled: enabled + direction: egress + )"; + + YAML::Node yamlNode = YAML::Load(yamlStr); + CollectorConfig config; + ASSERT_EQ(ConfigLoader(config).LoadConfiguration(yamlNode), ConfigLoader::SUCCESS) << "Input: " << yamlStr; + + auto runtime_config = config.GetRuntimeConfig(); + + EXPECT_TRUE(runtime_config.has_value()); + + EXPECT_EQ(Direction::EGRESS, config.ExternalIPsConf().GetDirection()); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::INGRESS)); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::EGRESS)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::BOTH)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::NONE)); +} + +TEST(CollectorConfigTest, TestIsEnabledBoth) { + std::string yamlStr = R"( + networking: + externalIps: + enabled: enabled + direction: both + )"; + + YAML::Node yamlNode = YAML::Load(yamlStr); + CollectorConfig config; + ASSERT_EQ(ConfigLoader(config).LoadConfiguration(yamlNode), ConfigLoader::SUCCESS) << "Input: " << yamlStr; + + auto runtime_config = config.GetRuntimeConfig(); + + EXPECT_TRUE(runtime_config.has_value()); + + EXPECT_EQ(Direction::BOTH, config.ExternalIPsConf().GetDirection()); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::INGRESS)); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::EGRESS)); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::BOTH)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::NONE)); +} + +TEST(CollectorConfigTest, TestIsEnabledNone) { + std::string yamlStr = R"( + networking: + externalIps: + enabled: disabled + )"; + + YAML::Node yamlNode = YAML::Load(yamlStr); + CollectorConfig config; + ASSERT_EQ(ConfigLoader(config).LoadConfiguration(yamlNode), ConfigLoader::SUCCESS) << "Input: " << yamlStr; + + auto runtime_config = config.GetRuntimeConfig(); + + EXPECT_TRUE(runtime_config.has_value()); + + EXPECT_EQ(Direction::NONE, config.ExternalIPsConf().GetDirection()); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::INGRESS)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::EGRESS)); + EXPECT_FALSE(config.ExternalIPsConf().IsEnabled(Direction::BOTH)); + EXPECT_TRUE(config.ExternalIPsConf().IsEnabled(Direction::NONE)); } } // namespace collector diff --git a/collector/test/ConfigLoaderTest.cpp b/collector/test/ConfigLoaderTest.cpp index 0ddfe16768..e4df3da05d 100644 --- a/collector/test/ConfigLoaderTest.cpp +++ b/collector/test/ConfigLoaderTest.cpp @@ -11,6 +11,7 @@ namespace collector { using namespace google::protobuf::util; +using Direction = ExternalIPsConfig::Direction; std::string ErrorsToString(const std::vector& errors) { std::stringstream ss; @@ -308,29 +309,49 @@ TEST(TestParserYaml, ValidationMode) { */ TEST(CollectorConfigTest, TestYamlConfigToConfigMultiple) { - std::vector> tests = { + std::vector> tests = { {R"( networking: externalIps: enabled: enabled )", - true}, + Direction::BOTH}, + {R"( + networking: + externalIps: + enabled: enabled + direction: ingress + )", + Direction::INGRESS}, + {R"( + networking: + externalIps: + enabled: enabled + direction: egress + )", + Direction::EGRESS}, + {R"( + networking: + externalIps: + enabled: enabled + direction: both + )", + Direction::BOTH}, {R"( networking: externalIps: enabled: DISABLED )", - false}, + Direction::NONE}, {R"( networking: externalIps: )", - false}, - { - R"( + Direction::NONE}, + {R"( networking: )", - false}, + Direction::NONE}, }; for (const auto& [yamlStr, expected] : tests) { @@ -342,12 +363,7 @@ TEST(CollectorConfigTest, TestYamlConfigToConfigMultiple) { EXPECT_TRUE(runtime_config.has_value()); - bool enabled = runtime_config.value() - .networking() - .external_ips() - .enabled() == sensor::ExternalIpsEnabled::ENABLED; - EXPECT_EQ(enabled, expected); - EXPECT_EQ(config.EnableExternalIPs(), expected); + EXPECT_EQ(config.ExternalIPsConf().GetDirection(), expected); } } diff --git a/collector/test/ConnTrackerTest.cpp b/collector/test/ConnTrackerTest.cpp index aa6542c083..a8457247cc 100644 --- a/collector/test/ConnTrackerTest.cpp +++ b/collector/test/ConnTrackerTest.cpp @@ -415,7 +415,7 @@ TEST(ConnTrackerTest, TestNormalizedEnableExternalIPs) { int64_t time_micros = 1000; ConnectionTracker tracker; - tracker.EnableExternalIPs(true); + tracker.SetExternalIPsConfig(ExternalIPsConfig(std::nullopt, true)); UnorderedMap> known_networks = {{Address::Family::IPV4, {IPNet(Address(35, 127, 1, 0), 24)}}}; tracker.UpdateKnownIPNetworks(std::move(known_networks)); @@ -1651,80 +1651,177 @@ TEST(ConnTrackerTest, TestConnectionStats) { EXPECT_EQ(stats.outbound.public_, 4); } -TEST(ConnTrackerTest, TestCloseNormalizedConnections) { - ConnectionTracker tracker; - - Endpoint a(Address(192, 168, 0, 1), 80); - Endpoint b(Address(255, 255, 255, 255), 9999); - - Connection conn("xyz", a, b, L4Proto::TCP, true); - int64_t connection_time = 990; - - ConnMap old_state = {{conn, ConnStatus(connection_time, true)}}; - ConnMap delta; - ConnMap expected_delta = {{conn, ConnStatus(connection_time, false)}}; - - tracker.CloseNormalizedConnections(&old_state, &delta); - - EXPECT_THAT(old_state, IsEmpty()); - EXPECT_THAT(delta, expected_delta); -} +TEST(ConnTrackerTest, TestExternalIPsConfigChangeEnableEgress) { + Endpoint ingress_local(IPNet(Address()), 80); + Endpoint ingress_remote(Address(223, 42, 0, 1), 0); + Endpoint ingress_remote_normalized(Address(255, 255, 255, 255), 0); -TEST(CloseNormalizedConnectionsTest, UnnormalizedConnectionsAreKept) { - ConnectionTracker tracker; + Endpoint egress_local = Endpoint(); + Endpoint egress_remote(Address(223, 42, 0, 2), 443); + Endpoint egress_remote_normalized(Address(255, 255, 255, 255), 443); - Endpoint a(Address(192, 168, 0, 1), 80); - Endpoint b(Address(192, 168, 1, 10), 9999); + Connection conn_ingress("xyz", ingress_local, ingress_remote, L4Proto::TCP, true); + Connection conn_ingress_normalized("xyz", ingress_local, ingress_remote_normalized, L4Proto::TCP, true); + Connection conn_egress("xyz", egress_local, egress_remote, L4Proto::TCP, false); + Connection conn_egress_normalized("xyz", egress_local, egress_remote_normalized, L4Proto::TCP, false); - Connection conn("xyz", a, b, L4Proto::TCP, true); int64_t connection_time = 990; - ConnMap old_state = {{conn, ConnStatus(connection_time, true)}}; - ConnMap delta; - ConnMap expected_old_state = {{conn, ConnStatus(connection_time, true)}}; - - tracker.CloseNormalizedConnections(&old_state, &delta); - - EXPECT_THAT(old_state, expected_old_state); - EXPECT_THAT(delta, IsEmpty()); -} - -TEST(ConnTrackerTest, TestCloseExternalUnnormalizedConnections) { - ConnectionTracker tracker; - - Endpoint a(Address(192, 168, 0, 1), 80); - Endpoint b(Address(11, 168, 1, 10), 9999); - - Connection conn("xyz", a, b, L4Proto::TCP, true); - int64_t connection_time = 990; - - ConnMap old_state = {{conn, ConnStatus(connection_time, true)}}; - ConnMap delta; - ConnMap expected_delta = {{conn, ConnStatus(connection_time, false)}}; - - tracker.CloseExternalUnnormalizedConnections(&old_state, &delta); - - EXPECT_THAT(old_state, IsEmpty()); - EXPECT_THAT(delta, expected_delta); -} - -TEST(CloseExternalUnnormalizedConnectionsTest, InternalConnectionsAreKept) { - ConnectionTracker tracker; - - Endpoint a(Address(192, 168, 0, 1), 80); - Endpoint b(Address(192, 168, 1, 10), 9999); - - Connection conn("xyz", a, b, L4Proto::TCP, true); - int64_t connection_time = 990; - - ConnMap old_state = {{conn, ConnStatus(connection_time, true)}}; - ConnMap delta; - ConnMap expected_old_state = {{conn, ConnStatus(connection_time, true)}}; - - tracker.CloseExternalUnnormalizedConnections(&old_state, &delta); - - EXPECT_THAT(old_state, expected_old_state); - EXPECT_THAT(delta, IsEmpty()); + struct TestStep { + ExternalIPsConfig::Direction previous_direction; + ExternalIPsConfig::Direction new_direction; + ConnMap old_state; + ConnMap resulting_old_state; + ConnMap expected_delta; + } testSteps[] = { + {// No change (enabled) + .previous_direction = ExternalIPsConfig::Direction::BOTH, + .new_direction = ExternalIPsConfig::Direction::BOTH, + .old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .resulting_old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .expected_delta = {}}, + {// No change (disabled) + .previous_direction = ExternalIPsConfig::Direction::NONE, + .new_direction = ExternalIPsConfig::Direction::NONE, + .old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .resulting_old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .expected_delta = {}}, + {// Enable EGRESS + .previous_direction = ExternalIPsConfig::Direction::NONE, + .new_direction = ExternalIPsConfig::Direction::EGRESS, + .old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)} /* closed */, + }, + .resulting_old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + }, + .expected_delta = { + {conn_egress_normalized, ConnStatus(connection_time, false)}, + }}, + {// Enable INGRESS + .previous_direction = ExternalIPsConfig::Direction::NONE, + .new_direction = ExternalIPsConfig::Direction::INGRESS, + .old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)} /* closed */, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .resulting_old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .expected_delta = { + {conn_ingress_normalized, ConnStatus(connection_time, false)}, + }}, + {// Disable EGRESS enable INGRESS + .previous_direction = ExternalIPsConfig::Direction::EGRESS, + .new_direction = ExternalIPsConfig::Direction::INGRESS, + .old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, /* closed */ + {conn_egress, ConnStatus(connection_time, true)} /* closed */, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .resulting_old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .expected_delta = { + {conn_ingress_normalized, ConnStatus(connection_time, false)}, + {conn_egress, ConnStatus(connection_time, false)}, + }}, + {// Disable INGRESS enable EGRESS + .previous_direction = ExternalIPsConfig::Direction::INGRESS, + .new_direction = ExternalIPsConfig::Direction::EGRESS, + .old_state = { + {conn_ingress, ConnStatus(connection_time, true)} /* closed */, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)} /* closed */, + }, + .resulting_old_state = { + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + }, + .expected_delta = { + {conn_ingress, ConnStatus(connection_time, false)}, + {conn_egress_normalized, ConnStatus(connection_time, false)}, + }}, + {// Disable EGRESS + .previous_direction = ExternalIPsConfig::Direction::BOTH, + .new_direction = ExternalIPsConfig::Direction::INGRESS, + .old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)} /* closed */, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .resulting_old_state = { + {conn_ingress, ConnStatus(connection_time, true)}, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .expected_delta = { + {conn_egress, ConnStatus(connection_time, false)}, + }}, + {// Disable INGRESS + .previous_direction = ExternalIPsConfig::Direction::BOTH, + .new_direction = ExternalIPsConfig::Direction::EGRESS, + .old_state = { + {conn_ingress, ConnStatus(connection_time, true)} /* closed */, + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .resulting_old_state = { + {conn_ingress_normalized, ConnStatus(connection_time, true)}, + {conn_egress, ConnStatus(connection_time, true)}, + {conn_egress_normalized, ConnStatus(connection_time, true)}, + }, + .expected_delta = { + {conn_ingress, ConnStatus(connection_time, false)}, + }}}; + + for (auto step : testSteps) { + ConnectionTracker tracker; + ConnMap delta; + + tracker.SetExternalIPsConfig(step.new_direction); + tracker.CloseConnectionsOnExternalIPsConfigChange( + step.previous_direction, + &step.old_state, + &delta); + + EXPECT_THAT(step.old_state, step.resulting_old_state); + EXPECT_THAT(delta, step.expected_delta); + } } TEST(ConnTrackerTest, TestShouldNormalizeConnection) { diff --git a/docs/references.md b/docs/references.md index 110b2757df..19966cda25 100644 --- a/docs/references.md +++ b/docs/references.md @@ -151,6 +151,36 @@ Whenever the configuration file is updated or created, collector will update the configuration. If the configuration file is deleted the configuration will revert to the default. The configuration file can be created after collector start up. +### Runtime-configuration + +When Collector is provided with a runtime configuration file as described in the previous +section, it is able to reconfigure itself dynamically (without a need for restart) if the +content of the file changes. + +The following attributes can be set using the runtime-configuration file : + +* `networking.externalIPs.enabled: ENABLED | DISABLED`: enable/disable the external-IPs feature. +Default value: `DISABLED` + +* `networking.externalIPs.direction: INGRESS | EGRESS | BOTH`: when external-IPs are enabled, +this attribute can restrict the direction in which it is effective. For instance, using `EGRESS` +will aggregate all the incoming connections and give all details for the outgoing ones. This can +be particularly useful to limit the load resulting from enabling external-IPs. +Default value: `BOTH` + +* `networking.maxConnectionsPerMinute: `: set a limit on the number of connections that can +be reported per container and per minute. +Default value: 2048 + +Here is an example of runtime-configuration to enable external-IPs for `EGRESS` only: + +``` +networking: + externalIps: + enabled: ENABLED + direction: EGRESS +``` + ### Other arguments * `--collection-method`: Which technology to use for data gathering. Either