diff --git a/falco.yaml b/falco.yaml index 4d7fd18fea4..657395995ad 100644 --- a/falco.yaml +++ b/falco.yaml @@ -492,6 +492,8 @@ webserver: # the appropriate number of threads based on the number of online cores in the system. threadiness: 0 listen_port: 8765 + # Can be an IPV4 or IPV6 address, defaults to IPV4 + listen_address: 0.0.0.0 k8s_healthz_endpoint: /healthz ssl_enabled: false ssl_certificate: /etc/falco/falco.pem diff --git a/unit_tests/falco/test_configuration.cpp b/unit_tests/falco/test_configuration.cpp index d109005e070..0714035c26c 100644 --- a/unit_tests/falco/test_configuration.cpp +++ b/unit_tests/falco/test_configuration.cpp @@ -174,3 +174,83 @@ TEST(Configuration, configuration_environment_variables) /* Clear the set environment variable after testing */ unsetenv(env_var_name.c_str()); } + +TEST(Configuration, configuration_webserver_ip) +{ + falco_configuration falco_config; + + std::vector valid_addresses = {"127.0.0.1", + "1.127.0.1", + "1.1.127.1", + "1.1.1.127", + "::", + "::1", + "1200:0000:AB00:1234:0000:2552:7777:1313", + "1200::AB00:1234:0000:2552:7777:1313", + "1200:0000:AB00:1234::2552:7777:1313", + "21DA:D3:0:2F3B:2AA:FF:FE28:9C5A", + "FE80:0000:0000:0000:0202:B3FF:FE1E:8329", + "0.0.0.0", + "9.255.255.255", + "11.0.0.0", + "126.255.255.255", + "129.0.0.0", + "169.253.255.255", + "169.255.0.0", + "172.15.255.255", + "172.32.0.0", + "191.0.1.255", + "192.88.98.255", + "192.88.100.0", + "192.167.255.255", + "192.169.0.0", + "198.17.255.255", + "223.255.255.255"}; + + for (const std::string &address: valid_addresses) { + std::string option = "webserver.listen_address="; + option.append(address); + + std::vector cmdline_config_options; + cmdline_config_options.push_back(option); + + EXPECT_NO_THROW(falco_config.init(cmdline_config_options)); + + ASSERT_EQ(falco_config.m_webserver_listen_address, address); + } + + std::vector invalid_addresses = {"327.0.0.1", + "1.327.0.1", + "1.1.327.1", + "1.1.1.327", + "12 7.0.0.1", + "127. 0.0.1", + "127.0. 0.1", + "127.0.0. 1", + "!27.0.0.1", + "1200: 0000:AB00:1234:0000:2552:7777:1313", + "1200:0000: AB00:1234:0000:2552:7777:1313", + "1200:0000:AB00: 1234:0000:2552:7777:1313", + "1200:0000:AB00:1234: 0000:2552:7777:1313", + "1200:0000:AB00:1234:0000: 2552:7777:1313", + "1200:0000:AB00:1234:0000:2552: 7777:1313", + "1200:0000:AB00:1234:0000:2552:7777: 1313", + "1200:0000:AB00:1234:0000:2552:7777:131G", + "1200:0000:AB00:1234:0000:2552:77Z7:1313", + "1200:0000:AB00:1234:0000:2G52:7777:1313", + "1200:0000:AB00:1234:0O00:2552:7777:1313", + "1200:0000:AB00:H234:0000:2552:7777:1313", + "1200:0000:IB00:1234:0000:2552:7777:1313", + "1200:0O00:AB00:1234:0000:2552:7777:1313", + "12O0:0000:AB00:1234:0000:2552:7777:1313",}; + + for (const std::string &address: invalid_addresses) { + std::string option = "webserver.listen_address="; + option.append(address); + + std::vector cmdline_config_options; + cmdline_config_options.push_back(option); + + EXPECT_ANY_THROW(falco_config.init(cmdline_config_options)); + } +} diff --git a/userspace/falco/app/actions/start_webserver.cpp b/userspace/falco/app/actions/start_webserver.cpp index a6f5b0c3073..b03f5ca0a8b 100644 --- a/userspace/falco/app/actions/start_webserver.cpp +++ b/userspace/falco/app/actions/start_webserver.cpp @@ -38,7 +38,9 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s std::string ssl_option = (s.config->m_webserver_ssl_enabled ? " (SSL)" : ""); falco_logger::log(LOG_INFO, "Starting health webserver with threadiness " + std::to_string(s.config->m_webserver_threadiness) - + ", listening on port " + + ", listening on " + + s.config->m_webserver_listen_address + + ":" + std::to_string(s.config->m_webserver_listen_port) + ssl_option + "\n"); @@ -46,6 +48,7 @@ falco::app::run_result falco::app::actions::start_webserver(falco::app::state& s s.offline_inspector, s.config->m_webserver_threadiness, s.config->m_webserver_listen_port, + s.config->m_webserver_listen_address, s.config->m_webserver_k8s_healthz_endpoint, s.config->m_webserver_ssl_certificate, s.config->m_webserver_ssl_enabled); diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 365ebf78e25..64f02620cf6 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -31,6 +31,11 @@ limitations under the License. #include "configuration.h" #include "logger.h" +#include + +// Reference: https://digitalfortress.tech/tips/top-15-commonly-used-regex/ +static re2::RE2 ip_address_re("((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))"); + falco_configuration::falco_configuration(): m_json_output(false), m_json_include_output_property(true), @@ -46,6 +51,7 @@ falco_configuration::falco_configuration(): m_webserver_enabled(false), m_webserver_threadiness(0), m_webserver_listen_port(8765), + m_webserver_listen_address("0.0.0.0"), m_webserver_k8s_healthz_endpoint("/healthz"), m_webserver_ssl_enabled(false), m_syscall_evt_drop_threshold(.1), @@ -285,6 +291,12 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h m_webserver_enabled = config.get_scalar("webserver.enabled", false); m_webserver_threadiness = config.get_scalar("webserver.threadiness", 0); m_webserver_listen_port = config.get_scalar("webserver.listen_port", 8765); + m_webserver_listen_address = config.get_scalar("webserver.listen_address", "0.0.0.0"); + if(!re2::RE2::FullMatch(m_webserver_listen_address, ip_address_re)) + { + throw std::logic_error("Error reading config file (" + config_name + "): webserver listen address \"" + m_webserver_listen_address + "\" is not a valid IP address"); + } + m_webserver_k8s_healthz_endpoint = config.get_scalar("webserver.k8s_healthz_endpoint", "/healthz"); m_webserver_ssl_enabled = config.get_scalar("webserver.ssl_enabled", false); m_webserver_ssl_certificate = config.get_scalar("webserver.ssl_certificate", "/etc/falco/falco.pem"); diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index e53c1189df0..47a672f67d2 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -85,6 +85,7 @@ class falco_configuration bool m_webserver_enabled; uint32_t m_webserver_threadiness; uint32_t m_webserver_listen_port; + std::string m_webserver_listen_address; std::string m_webserver_k8s_healthz_endpoint; bool m_webserver_ssl_enabled; std::string m_webserver_ssl_certificate; diff --git a/userspace/falco/webserver.cpp b/userspace/falco/webserver.cpp index 36070f1f79a..fe6ae0ceae4 100644 --- a/userspace/falco/webserver.cpp +++ b/userspace/falco/webserver.cpp @@ -29,6 +29,7 @@ void falco_webserver::start( const std::shared_ptr& inspector, uint32_t threadiness, uint32_t listen_port, + std::string& listen_address, std::string& healthz_endpoint, std::string &ssl_certificate, bool ssl_enabled) @@ -77,11 +78,11 @@ void falco_webserver::start( std::atomic failed; failed.store(false, std::memory_order_release); - m_server_thread = std::thread([this, listen_port, &failed] + m_server_thread = std::thread([this, listen_address, listen_port, &failed] { try { - this->m_server->listen("0.0.0.0", listen_port); + this->m_server->listen(listen_address, listen_port); } catch(std::exception &e) { diff --git a/userspace/falco/webserver.h b/userspace/falco/webserver.h index 8a2e3a2f6ab..ad00beee687 100644 --- a/userspace/falco/webserver.h +++ b/userspace/falco/webserver.h @@ -37,6 +37,7 @@ class falco_webserver const std::shared_ptr& inspector, uint32_t threadiness, uint32_t listen_port, + std::string& list_address, std::string& healthz_endpoint, std::string &ssl_certificate, bool ssl_enabled);