Merge pull request #190 from openappsec/Sep_17_2024-Dev

sync code
This commit is contained in:
Daniel-Eisenberg 2024-09-30 14:53:51 +03:00 committed by GitHub
commit 4a7336b276
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
143 changed files with 1886 additions and 380 deletions

View File

@ -1,4 +1,3 @@
add_subdirectory(report_messaging)
add_subdirectory(http_manager)
add_subdirectory(signal_handler)
add_subdirectory(gradual_deployment)

View File

@ -39,6 +39,8 @@ USE_DEBUG_FLAG(D_ATTACHMENT_REGISTRATION);
using namespace std;
static const AlertInfo alert(AlertTeam::CORE, "attachment registrator");
class AttachmentRegistrator::Impl
{
public:
@ -163,7 +165,7 @@ private:
break;
}
default:
dbgAssert(false) << "Unsupported Attachment " << static_cast<int>(type);
dbgAssert(false) << alert << "Unsupported Attachment " << static_cast<int>(type);
}
if (!family_id.empty()) handler_path << family_id << "_";
@ -175,7 +177,9 @@ private:
string
genRegCommand(const string &family_id, const uint num_of_members, const AttachmentType type) const
{
dbgAssert(num_of_members > 0) << "Failed to generate a registration command for an empty group of attachments";
dbgAssert(num_of_members > 0)
<< alert
<< "Failed to generate a registration command for an empty group of attachments";
static const string registration_format = "/etc/cp/watchdog/cp-nano-watchdog --register ";
stringstream registration_command;
@ -187,7 +191,7 @@ private:
break;
}
default:
dbgAssert(false) << "Unsupported Attachment " << static_cast<int>(type);
dbgAssert(false) << alert << "Unsupported Attachment " << static_cast<int>(type);
}
if (!family_id.empty()) registration_command << " --family " << family_id;
@ -265,7 +269,7 @@ private:
return -1;
}
dbgAssert(new_socket.unpack() > 0) << "Generated socket is OK yet negative";
dbgAssert(new_socket.unpack() > 0) << alert << "Generated socket is OK yet negative";
return new_socket.unpack();
}
@ -281,7 +285,7 @@ private:
}
I_Socket::socketFd client_socket = accepted_socket.unpack();
dbgAssert(client_socket > 0) << "Generated client socket is OK yet negative";
dbgAssert(client_socket > 0) << alert << "Generated client socket is OK yet negative";
auto close_socket_on_exit = make_scope_exit([&]() { i_socket->closeSocket(client_socket); });
Maybe<uint8_t> attachment_id = readNumericParam(client_socket);
@ -375,7 +379,7 @@ private:
}
I_Socket::socketFd client_socket = accepted_socket.unpack();
dbgAssert(client_socket > 0) << "Generated client socket is OK yet negative";
dbgAssert(client_socket > 0) << alert << "Generated client socket is OK yet negative";
auto close_socket_on_exit = make_scope_exit([&]() { i_socket->closeSocket(client_socket); });
Maybe<AttachmentType> attachment_type = readAttachmentType(client_socket);

View File

@ -76,6 +76,7 @@ using namespace std;
using ChunkType = ngx_http_chunk_type_e;
static const uint32_t corrupted_session_id = CORRUPTED_SESSION_ID;
static const AlertInfo alert(AlertTeam::CORE, "nginx attachment");
class FailopenModeListener : public Listener<FailopenModeEvent>
{
@ -410,7 +411,10 @@ private:
bool
registerAttachmentProcess(uint32_t nginx_user_id, uint32_t nginx_group_id, I_Socket::socketFd new_socket)
{
dbgAssert(server_sock > 0) << "Registration attempt occurred while registration socket is uninitialized";
dbgAssert(server_sock > 0)
<< alert
<< "Registration attempt occurred while registration socket is uninitialized";
#ifdef FAILURE_TEST
bool did_fail_on_purpose = false;
#endif
@ -802,10 +806,10 @@ private:
case ChunkType::HOLD_DATA:
return "HOLD_DATA";
case ChunkType::COUNT:
dbgAssert(false) << "Invalid 'COUNT' ChunkType";
dbgAssert(false) << alert << "Invalid 'COUNT' ChunkType";
return "";
}
dbgAssert(false) << "ChunkType was not handled by the switch case";
dbgAssert(false) << alert << "ChunkType was not handled by the switch case";
return "";
}
@ -1582,7 +1586,7 @@ private:
case WAIT:
return "WAIT";
}
dbgAssert(false) << "Invalid EventVerdict enum: " << static_cast<int>(verdict.getVerdict());
dbgAssert(false) << alert << "Invalid EventVerdict enum: " << static_cast<int>(verdict.getVerdict());
return string();
}
@ -1633,13 +1637,14 @@ private:
return false;
}
dbgAssert(sock.unpack() > 0) << "The generated server socket is OK, yet negative";
dbgAssert(sock.unpack() > 0) << alert << "The generated server socket is OK, yet negative";
server_sock = sock.unpack();
I_MainLoop::Routine accept_attachment_routine =
[this] ()
{
dbgAssert(inst_awareness->getUniqueID().ok())
<< alert
<< "NGINX attachment Initialized without Instance Awareness";
bool did_fail_on_purpose = false;
@ -1652,7 +1657,7 @@ private:
<< (did_fail_on_purpose ? "Intentional Failure" : new_sock.getErr());
return;
}
dbgAssert(new_sock.unpack() > 0) << "The generated client socket is OK, yet negative";
dbgAssert(new_sock.unpack() > 0) << alert << "The generated client socket is OK, yet negative";
I_Socket::socketFd new_attachment_socket = new_sock.unpack();
Maybe<string> uid = getUidFromSocket(new_attachment_socket);
@ -1711,7 +1716,9 @@ private:
Maybe<string>
getUidFromSocket(I_Socket::socketFd new_attachment_socket)
{
dbgAssert(server_sock > 0) << "Registration attempt occurred while registration socket is uninitialized";
dbgAssert(server_sock > 0)
<< alert
<< "Registration attempt occurred while registration socket is uninitialized";
bool did_fail_on_purpose = false;
DELAY_IF_NEEDED(IntentionalFailureHandler::FailureType::ReceiveDataFromSocket);

View File

@ -312,8 +312,6 @@ UsersAllIdentifiersConfig::setXFFValuesToOpaqueCtx(const HttpHeader &header, Ext
return;
}
NginxAttachmentOpaque &opaque = i_transaction_table->getState<NginxAttachmentOpaque>();
opaque.setSavedData(HttpTransactionData::xff_vals_ctx, header.getValue());
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "xff found, value from header: " << static_cast<string>(header.getValue());
auto value = parseXForwardedFor(header.getValue());
if (!value.ok()) {
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Could not extract source identifier from X-Forwarded-For header";
@ -325,6 +323,10 @@ UsersAllIdentifiersConfig::setXFFValuesToOpaqueCtx(const HttpHeader &header, Ext
dbgDebug(D_NGINX_ATTACHMENT_PARSER)
<< "Added source identifir to XFF "
<< value.unpack();
opaque.setSavedData(HttpTransactionData::xff_vals_ctx, header.getValue());
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
<< "XFF found, set ctx with value from header: "
<< static_cast<string>(header.getValue());
} else {
opaque.setSavedData(HttpTransactionData::proxy_ip_ctx, value.unpack());
}

View File

@ -128,7 +128,7 @@ private:
break;
}
default:
dbgAssert(false) << "Unsupported IP type";
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "gradual deployment") << "Unsupported IP type";
}
return address;
}

View File

@ -46,7 +46,10 @@ operator<<(ostream &os, const EventVerdict &event)
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_WAIT: return os << "Wait";
}
dbgAssert(false) << "Illegal Event Verdict value: " << static_cast<uint>(event.getVerdict());
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "http manager")
<< "Illegal Event Verdict value: "
<< static_cast<uint>(event.getVerdict());
return os;
}
@ -321,8 +324,11 @@ private:
state.setApplicationVerdict(respond.first, respond.second.getVerdict());
}
return state.getCurrVerdict();
FilterVerdict aggregated_verdict = state.getCurrVerdict();
if (aggregated_verdict.getVerdict() == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP) {
SecurityAppsDropEvent(state.getCurrentDropVerdictCausers()).notify();
}
return aggregated_verdict;
}
static void

View File

@ -69,6 +69,7 @@ HttpManagerOpaque::getCurrVerdict() const
break;
default:
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "http manager")
<< "Received unknown verdict "
<< static_cast<int>(app_verdic_pair.second);
}
@ -77,6 +78,25 @@ HttpManagerOpaque::getCurrVerdict() const
return accepted_apps == applications_verdicts.size() ? ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT : verdict;
}
std::set<std::string>
HttpManagerOpaque::getCurrentDropVerdictCausers() const
{
std::set<std::string> causers;
if (manager_verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP) {
causers.insert(HTTP_MANAGER_NAME);
}
for (const auto &app_verdic_pair : applications_verdicts) {
bool was_dropped = app_verdic_pair.second == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
dbgTrace(D_HTTP_MANAGER)
<< "The verdict from: " << app_verdic_pair.first
<< (was_dropped ? " is \"drop\"" : " is not \"drop\" ");
if (was_dropped) {
causers.insert(app_verdic_pair.first);
}
}
return causers;
}
void
HttpManagerOpaque::saveCurrentDataToCache(const Buffer &full_data)
{

View File

@ -20,6 +20,8 @@
#include "table_opaque.h"
#include "nginx_attachment_common.h"
static const std::string HTTP_MANAGER_NAME = "HTTP Manager";
class HttpManagerOpaque : public TableOpaqueSerialize<HttpManagerOpaque>
{
public:
@ -30,6 +32,7 @@ public:
void setManagerVerdict(ngx_http_cp_verdict_e verdict) { manager_verdict = verdict; }
ngx_http_cp_verdict_e getManagerVerdict() const { return manager_verdict; }
ngx_http_cp_verdict_e getCurrVerdict() const;
std::set<std::string> getCurrentDropVerdictCausers() const;
void saveCurrentDataToCache(const Buffer &full_data);
void setUserDefinedValue(const std::string &value) { user_defined_value = value; }
Maybe<std::string> getUserDefinedValue() const { return user_defined_value; }

View File

@ -21,6 +21,7 @@
#include "i_shell_cmd.h"
#include "i_orchestration_status.h"
#include "component.h"
#include "i_service_controller.h"
class HealthChecker
:
@ -29,7 +30,8 @@ class HealthChecker
Singleton::Consume<I_Socket>,
Singleton::Consume<I_Health_Check_Manager>,
Singleton::Consume<I_ShellCmd>,
Singleton::Consume<I_OrchestrationStatus>
Singleton::Consume<I_OrchestrationStatus>,
Singleton::Consume<I_ServiceController>
{
public:
HealthChecker();

View File

@ -50,9 +50,11 @@ public:
position(mod_position)
{
dbgAssert(mod_type != ModificationType::APPEND || position == injection_pos_irrelevant)
<< AlertInfo(AlertTeam::CORE, "http manager")
<< "Injection position is not applicable to a modification of type \"Append\"";
dbgAssert(mod_type != ModificationType::INJECT || position >= 0)
<< AlertInfo(AlertTeam::CORE, "http manager")
<< "Invalid injection position: must be non-negative. Position: "
<< position;
}
@ -166,6 +168,7 @@ private:
}
default:
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "http manager")
<< "Unknown type of ModificationType: "
<< static_cast<int>(modification_type);
}

View File

@ -183,4 +183,16 @@ class WaitTransactionEvent : public Event<WaitTransactionEvent, EventVerdict>
{
};
class SecurityAppsDropEvent : public Event<SecurityAppsDropEvent>
{
public:
SecurityAppsDropEvent(
const std::set<std::string> &apps_names)
:
apps_names(apps_names) {}
const std::set<std::string> & getAppsNames() const { return apps_names; }
private:
const std::set<std::string> apps_names;
};
#endif // __HTTP_INSPECTION_EVENTS_H__

View File

@ -66,6 +66,8 @@ public:
virtual std::map<std::string, std::vector<PortNumber>> getServiceToPortMap() = 0;
virtual bool getServicesPolicyStatus() const = 0;
protected:
virtual ~I_ServiceController() {}
};

View File

@ -115,7 +115,7 @@ public:
case ResourceFileType::VIRTUAL_SETTINGS: return "virtualSettings";
case ResourceFileType::VIRTUAL_POLICY: return "virtualPolicy";
default:
dbgAssert(false) << "Unknown file type";
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "update process") << "Unknown file type";
}
return std::string();
}

View File

@ -56,7 +56,7 @@ private:
if (mapped_type.second == type) return mapped_type.first;
}
dbgAssert(false) << "Unsupported type " << static_cast<int>(type);
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "packaging") << "Unsupported type " << static_cast<int>(type);
// Just satisfying the compiler, this return never reached
return std::string();
}

View File

@ -7,24 +7,28 @@ static const std::string product_name = getenv("DOCKER_RPM_ENABLED") ? "CloudGua
static const std::string default_cp_cert_file = "/etc/cp/cpCert.pem";
static const std::string default_cp_key_file = "/etc/cp/cpKey.key";
static const std::string default_rpm_conf_path = "/etc/cp/conf/rpmanager/";
static const std::string default_certificate_path = "/etc/cp/rpmanager/certs";
static const std::string default_manual_certs_path = "/etc/cp/rpmanager/manualCerts/";
static const std::string default_config_path = "/etc/cp/conf/rpmanager/servers";
static const std::string default_rpm_prepare_path = "/etc/cp/conf/rpmanager/prepare/servers";
static const std::string default_nginx_log_files_path = "/var/log/nginx/";
static const std::string default_additional_files_path = "/etc/cp/conf/rpmanager/include";
static const std::string default_server_config = "additional_server_config.conf";
static const std::string default_location_config = "additional_location_config.conf";
static const std::string default_trusted_ca_suffix = "_user_ca_bundle.crt";
static const std::string default_nginx_log_files_path = "/var/log/nginx/";
static const std::string default_log_files_host_path = "/var/log/nano_agent/rpmanager/nginx_log/";
static const std::string default_config_path = "/etc/cp/conf/rpmanager/servers";
static const std::string default_template_path = "/etc/cp/conf/rpmanager/nginx-template-clear";
static const std::string default_manual_certs_path = "/etc/cp/rpmanager/manualCerts/";
static const std::string default_server_certificate_path = "/etc/cp/rpmanager/certs/sslCertificate_";
static const std::string default_server_certificate_key_path = "/etc/cp/rpmanager/certs/sslPrivateKey_";
static const std::string default_container_name = "cp_nginx_gaia";
static const std::string default_docker_image = "cp_nginx_gaia";
static const std::string default_nginx_config_file = "/etc/cp/conf/rpmanager/nginx.conf";
static const std::string default_prepare_nginx_config_file = "/etc/cp/conf/rpmanager/nginx_prepare.conf";
static const std::string default_global_conf_template = "/etc/cp/conf/rpmanager/nginx-conf-template";
static const std::string default_nginx_config_include_file =
"/etc/cp/conf/rpmanager/servers/nginx_conf_include";
"/etc/cp/conf/rpmanager/servers/nginx_conf_include.conf";
static const std::string default_global_conf_include_template =
"/etc/cp/conf/rpmanager/nginx-conf-include-template";
static const std::string default_global_conf_include_template_no_responses =

View File

@ -0,0 +1,39 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __SERVICE_HEALTH_STATUS_H__
#define __SERVICE_HEALTH_STATUS_H__
#include "singleton.h"
#include "i_rest_api.h"
#include "i_environment.h"
#include "component.h"
class ServiceHealthStatus
:
public Component,
Singleton::Consume<I_RestApi>,
Singleton::Consume<I_Environment>
{
public:
ServiceHealthStatus();
~ServiceHealthStatus();
void init() override;
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif // __SERVICE_HEALTH_STATUS_H__

View File

@ -34,6 +34,8 @@ class I_Messaging;
class I_AgentDetails;
class I_Encryptor;
const std::string WAAP_APPLICATION_NAME = "waap application";
class WaapComponent
:
public Component,

View File

@ -563,7 +563,10 @@ Packet::parsePacket(PktType type, IPType proto)
return parseFromL3v6();
}
default: {
dbgAssert(false) << "Unknown (neither IPv4, nor IPv6), or uninitialized packet type: " << proto;
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "packet")
<< "Unknown (neither IPv4, nor IPv6), or uninitialized packet type: "
<< proto;
}
}

View File

@ -43,7 +43,9 @@ PendingKey::print(ostream &os) const
size_t
PendingKey::hash() const
{
dbgAssert(src.type != IPType::UNINITIALIZED) << "PendingKey::hash was called on an uninitialized object";
dbgAssert(src.type != IPType::UNINITIALIZED)
<< AlertInfo(AlertTeam::CORE, "pending key")
<< "PendingKey::hash was called on an uninitialized object";
size_t seed = 0;
hashCombine(seed, static_cast<u_char>(src.type));
hashCombine(seed, src.proto);

View File

@ -1,3 +0,0 @@
link_directories(${BOOST_ROOT}/lib)
add_unit_test(report_messaging_ut "report_messaging_ut.cc" "report_messaging;report;messaging;singleton;-lboost_regex")

View File

@ -67,18 +67,18 @@ public:
dbgTrace(D_GEO_FILTER) << getListenerName() << " new transaction event";
if (!event.isLastHeader()) return EventVerdict(ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT);
std::set<std::string> xff_set;
std::set<std::string> ip_set;
auto env = Singleton::Consume<I_Environment>::by<HttpGeoFilter>();
auto maybe_xff = env->get<std::string>(HttpTransactionData::xff_vals_ctx);
if (!maybe_xff.ok()) {
dbgTrace(D_GEO_FILTER) << "failed to get xff vals from env";
} else {
xff_set = split(maybe_xff.unpack(), ',');
ip_set = split(maybe_xff.unpack(), ',');
}
dbgDebug(D_GEO_FILTER) << getListenerName() << " last header, start lookup";
if (xff_set.size() > 0) {
removeTrustedIpsFromXff(xff_set);
if (ip_set.size() > 0) {
removeTrustedIpsFromXff(ip_set);
} else {
dbgDebug(D_GEO_FILTER) << "xff not found in headers";
}
@ -90,14 +90,14 @@ public:
}
auto source_ip = convertIpAddrToString(maybe_source_ip.unpack());
xff_set.insert(source_ip);
ip_set.insert(source_ip);
ngx_http_cp_verdict_e exception_verdict = getExceptionVerdict(xff_set);
ngx_http_cp_verdict_e exception_verdict = getExceptionVerdict(ip_set);
if (exception_verdict != ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT) {
return EventVerdict(exception_verdict);
}
ngx_http_cp_verdict_e geo_lookup_verdict = getGeoLookupVerdict(xff_set);
ngx_http_cp_verdict_e geo_lookup_verdict = getGeoLookupVerdict(ip_set);
if (geo_lookup_verdict != ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT) {
return EventVerdict(geo_lookup_verdict);
}
@ -469,5 +469,6 @@ void
HttpGeoFilter::preload()
{
registerExpectedConfiguration<GeoConfig>("rulebase", "httpGeoFilter");
registerExpectedConfiguration<UsersAllIdentifiersConfig>("rulebase", "usersIdentifiers");
registerConfigLoadCb([this]() { pimpl->loadDefaultAction(); });
}

View File

@ -43,7 +43,10 @@ CompoundProtection::Impl::getMatch(const set<PMPattern> &matched) const
case Operation::ORDERED_AND: return getMatchOrderedAnd(matched);
}
dbgAssert(false) << "Unknown compound operation: " << static_cast<uint>(operation);
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "ips")
<< "Unknown compound operation: "
<< static_cast<uint>(operation);
return MatchType::NO_MATCH;
}

View File

@ -8,7 +8,9 @@ IPSConfiguration::Context::Context(ContextType _type, uint history) : type(_type
uint
IPSConfiguration::Context::getHistorySize() const
{
dbgAssert(type == ContextType::HISTORY) << "Try to access history size for non-history context";
dbgAssert(type == ContextType::HISTORY)
<< AlertInfo(AlertTeam::CORE, "ips")
<< "Try to access history size for non-history context";
return history_size;
}
@ -69,6 +71,8 @@ uint
IPSConfiguration::getHistorySize(const string &name) const
{
auto context = context_config.find(name);
dbgAssert(context != context_config.end()) << "Try to access history size for non-exiting context";
dbgAssert(context != context_config.end())
<< AlertInfo(AlertTeam::CORE, "ips")
<< "Try to access history size for non-exiting context";
return context->second.getHistorySize();
}

View File

@ -84,7 +84,7 @@ IPSSignatureMetaData::getSeverityString() const
return "Critical";
}
dbgAssert(false) << "Illegal severity value: " << static_cast<uint>(severity);
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "ips") << "Illegal severity value: " << static_cast<uint>(severity);
return "Critical";
}
@ -116,7 +116,10 @@ IPSSignatureMetaData::getPerformanceString() const
return "Critical";
}
dbgAssert(false) << "Illegal performance value: " << static_cast<uint>(performance);
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "ips")
<< "Illegal performance value: "
<< static_cast<uint>(performance);
return "Critical";
}

View File

@ -19,7 +19,14 @@ using namespace std;
USE_DEBUG_FLAG(D_LOCAL_POLICY);
// LCOV_EXCL_START Reason: no test exist
static const set<string> valid_modes = {"prevent-learn", "detect-learn", "prevent", "detect", "inactive"};
static const set<string> valid_modes = {
"prevent-learn",
"detect-learn",
"prevent",
"detect",
"inactive",
"as-top-level"
};
static const set<string> valid_confidences = {"medium", "high", "critical"};
void
@ -138,15 +145,11 @@ AppSecPracticeWebAttacks::load(cereal::JSONInputArchive &archive_in)
dbgWarning(D_LOCAL_POLICY) << "AppSec practice override mode invalid: " << mode;
}
if (getMode() == "Prevent") {
parseAppsecJSONKey<string>("minimum-confidence", minimum_confidence, archive_in, "critical");
if (valid_confidences.count(minimum_confidence) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec practice override minimum confidence invalid: "
<< minimum_confidence;
}
} else {
minimum_confidence = "Transparent";
parseAppsecJSONKey<string>("minimum-confidence", minimum_confidence, archive_in, "critical");
if (valid_confidences.count(minimum_confidence) == 0) {
dbgWarning(D_LOCAL_POLICY)
<< "AppSec practice override minimum confidence invalid: "
<< minimum_confidence;
}
parseAppsecJSONKey<int>("max-body-size-kb", max_body_size_kb, archive_in, 1000000);
parseAppsecJSONKey<int>("max-header-size-bytes", max_header_size_bytes, archive_in, 102400);
@ -189,7 +192,10 @@ AppSecPracticeWebAttacks::getMode(const string &default_mode) const
{
if (isModeInherited(mode) || (key_to_practices_val2.find(mode) == key_to_practices_val2.end())) {
dbgError(D_LOCAL_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode;
return default_mode;
if(key_to_practices_val2.find(default_mode) == key_to_practices_val2.end()) {
return default_mode;
}
return key_to_practices_val2.at(default_mode);
}
return key_to_practices_val2.at(mode);
}
@ -428,7 +434,6 @@ WebAppSection::WebAppSection(
practice_id(_practice_id),
practice_name(_practice_name),
context(_context),
web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()),
web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)),
csrf_protection_mode("Disabled"),
open_redirect_mode("Disabled"),
@ -438,6 +443,9 @@ WebAppSection::WebAppSection(
trusted_sources({ parsed_trusted_sources })
{
web_attack_mitigation = web_attack_mitigation_mode != "Disabled";
web_attack_mitigation_severity =
web_attack_mitigation_mode != "Prevent" ? "Transparent" :
parsed_appsec_spec.getWebAttacks().getMinimumConfidence();
web_attack_mitigation_action =
web_attack_mitigation_mode != "Prevent" ? "Transparent" :
web_attack_mitigation_severity == "critical" ? "low" :
@ -470,6 +478,7 @@ WebAppSection::WebAppSection(
const string &_context,
const string &_web_attack_mitigation_severity,
const string &_web_attack_mitigation_mode,
const string &_bot_protection,
const PracticeAdvancedConfig &_practice_advanced_config,
const AppsecPracticeAntiBotSection &_anti_bots,
const LogTriggerSection &parsed_log_trigger,
@ -486,6 +495,7 @@ WebAppSection::WebAppSection(
context(_context),
web_attack_mitigation_severity(_web_attack_mitigation_severity),
web_attack_mitigation_mode(_web_attack_mitigation_mode),
bot_protection(_bot_protection),
practice_advanced_config(_practice_advanced_config),
anti_bots(_anti_bots),
trusted_sources({ parsed_trusted_sources })
@ -514,7 +524,6 @@ void
WebAppSection::save(cereal::JSONOutputArchive &out_ar) const
{
string disabled_str = "Disabled";
string detect_str = "Detect";
vector<string> empty_list;
out_ar(
cereal::make_nvp("context", context),
@ -542,7 +551,7 @@ WebAppSection::save(cereal::JSONOutputArchive &out_ar) const
cereal::make_nvp("waapParameters", empty_list),
cereal::make_nvp("botProtection", false),
cereal::make_nvp("antiBot", anti_bots),
cereal::make_nvp("botProtection_v2", detect_str)
cereal::make_nvp("botProtection_v2", bot_protection != "" ? bot_protection : string("Detect"))
);
}

View File

@ -290,6 +290,7 @@ public:
const std::string &_context,
const std::string &_web_attack_mitigation_severity,
const std::string &_web_attack_mitigation_mode,
const std::string &_bot_protection,
const PracticeAdvancedConfig &_practice_advanced_config,
const AppsecPracticeAntiBotSection &_anti_bots,
const LogTriggerSection &parsed_log_trigger,
@ -315,6 +316,7 @@ private:
std::string csrf_protection_mode;
std::string open_redirect_mode;
std::string error_disclosure_mode;
std::string bot_protection;
bool web_attack_mitigation;
std::vector<TriggersInWaapSection> triggers;
PracticeAdvancedConfig practice_advanced_config;

View File

@ -508,30 +508,20 @@ private:
bool is_temporary;
};
class NewAppSecWebBotsURI
{
public:
void load(cereal::JSONInputArchive &archive_in);
const std::string & getURI() const;
private:
std::string uri;
};
class NewAppSecPracticeAntiBot
{
public:
std::vector<std::string> getIjectedUris() const;
std::vector<std::string> getValidatedUris() const;
const std::vector<std::string> & getIjectedUris() const;
const std::vector<std::string> & getValidatedUris() const;
const std::string & getMode() const;
void load(cereal::JSONInputArchive &archive_in);
void save(cereal::JSONOutputArchive &out_ar) const;
private:
std::string override_mode;
std::vector<NewAppSecWebBotsURI> injected_uris;
std::vector<NewAppSecWebBotsURI> validated_uris;
std::vector<std::string> injected_uris;
std::vector<std::string> validated_uris;
};
class NewAppSecWebAttackProtections

View File

@ -39,7 +39,7 @@ public:
bool _logToAgent,
bool _logToCef,
bool _logToCloud,
bool _logToContainerService,
bool _logTolocalTuning,
bool _logToSyslog,
bool _responseBody,
bool _tpDetect,
@ -73,7 +73,7 @@ private:
bool logToAgent;
bool logToCef;
bool logToCloud;
bool logToContainerService;
bool logTolocalTuning;
bool logToSyslog;
bool responseBody;
bool tpDetect;

View File

@ -180,12 +180,16 @@ NewAppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
} else {
cloud = false;
}
auto mode = Singleton::Consume<I_AgentDetails>::by<NewAppsecTriggerLogDestination>()->getOrchestrationMode();
auto env_type = Singleton::Consume<I_EnvDetails>::by<NewAppsecTriggerLogDestination>()->getEnvType();
bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S);
// BC try load previous name. TODO: update CRD
parseAppsecJSONKey<bool>("k8s-service", container_service, archive_in, k8s_service_default);
parseAppsecJSONKey<bool>("container-service", container_service, archive_in, container_service);
bool local_tuning_default = false;
// check ENV VAR LOCAL_TUNING_ENABLED
char * tuning_enabled = getenv("LOCAL_TUNING_ENABLED");
if (tuning_enabled != NULL) {
for (unsigned int i = 0; i < strlen(tuning_enabled); i++) {
tuning_enabled[i] = tolower(tuning_enabled[i]);
}
local_tuning_default = string(tuning_enabled) == "true";
}
parseAppsecJSONKey<bool>("local-tuning", container_service, archive_in, local_tuning_default);
NewStdoutLogging stdout_log;
parseAppsecJSONKey<NewStdoutLogging>("stdout", stdout_log, archive_in);

View File

@ -50,6 +50,13 @@ static const std::unordered_map<std::string, std::string> key_to_mode_val = {
{ "detect", "Detect"},
{ "inactive", "Inactive"}
};
static const std::unordered_map<std::string, std::string> anti_bot_key_to_mode_val = {
{ "prevent-learn", "Prevent"},
{ "detect-learn", "Detect"},
{ "prevent", "Prevent"},
{ "detect", "Detect"},
{ "inactive", "Disabled"}
};
static const std::unordered_map<std::string, uint64_t> unit_to_int = {
{ "bytes", 1},
{ "KB", 1024},
@ -81,57 +88,44 @@ getModeWithDefault(
return key_to_val.at(mode);
}
void
NewAppSecWebBotsURI::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots URI";
parseAppsecJSONKey<string>("uri", uri, archive_in);
}
const string &
NewAppSecWebBotsURI::getURI() const
{
return uri;
}
std::vector<std::string>
const std::vector<std::string> &
NewAppSecPracticeAntiBot::getIjectedUris() const
{
vector<string> injected;
for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
return injected;
return injected_uris;
}
std::vector<std::string>
const std::vector<std::string> &
NewAppSecPracticeAntiBot::getValidatedUris() const
{
vector<string> validated;
for (const NewAppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI());
return validated;
return validated_uris;
}
const std::string &
NewAppSecPracticeAntiBot::getMode() const
{
return override_mode;
}
void
NewAppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Web Bots";
parseAppsecJSONKey<vector<NewAppSecWebBotsURI>>("injectedUris", injected_uris, archive_in);
parseAppsecJSONKey<vector<NewAppSecWebBotsURI>>("validatedUris", validated_uris, archive_in);
parseMandatoryAppsecJSONKey<string>("overrideMode", override_mode, archive_in, "inactive");
if (valid_modes.count(override_mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Web Bots override mode invalid: " << override_mode;
string mode;
parseAppsecJSONKey<vector<string>>("injectedUris", injected_uris, archive_in);
parseAppsecJSONKey<vector<string>>("validatedUris", validated_uris, archive_in);
parseMandatoryAppsecJSONKey<string>("overrideMode", mode, archive_in, "inactive");
if (valid_modes.count(mode) == 0) {
dbgWarning(D_LOCAL_POLICY) << "AppSec Web Bots override mode invalid: " << mode;
}
override_mode = anti_bot_key_to_mode_val.at(mode);
}
void
NewAppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const
{
vector<string> injected;
vector<string> validated;
for (const NewAppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI());
for (const NewAppSecWebBotsURI &uri : validated_uris) validated.push_back(uri.getURI());
out_ar(
cereal::make_nvp("injected", injected),
cereal::make_nvp("validated", validated)
cereal::make_nvp("injected", injected_uris),
cereal::make_nvp("validated", validated_uris)
);
}

View File

@ -555,7 +555,7 @@ extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_sp
bool webHeaders = trigger_spec.getAppsecTriggerExtendedLogging().isHttpHeaders();
bool webBody = trigger_spec.getAppsecTriggerExtendedLogging().isRequestBody();
bool logToCloud = trigger_spec.getAppsecTriggerLogDestination().getCloud();
bool logToContainerService = trigger_spec.getAppsecTriggerLogDestination().isContainerNeeded();
bool logTolocalTuning = trigger_spec.getAppsecTriggerLogDestination().isContainerNeeded();
bool logToAgent = trigger_spec.getAppsecTriggerLogDestination().isAgentLocal();
bool beautify_logs = trigger_spec.getAppsecTriggerLogDestination().shouldBeautifyLogs();
bool logToCef = trigger_spec.getAppsecTriggerLogDestination().isCefNeeded();
@ -582,7 +582,7 @@ extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_sp
logToAgent,
logToCef,
logToCloud,
logToContainerService,
logTolocalTuning,
logToSyslog,
responseBody,
tpDetect,
@ -1236,6 +1236,7 @@ PolicyMakerUtils::createWebAppSection(
rule_config.getContext(),
apssec_practice.getWebAttacks().getMinimumConfidence(practice_mode),
apssec_practice.getWebAttacks().getMode(practice_mode),
apssec_practice.getAntiBot().getMode(),
practice_advance_config,
apssec_practice.getAntiBot(),
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]],

View File

@ -30,7 +30,7 @@ LogTriggerSection::LogTriggerSection(
bool _logToAgent,
bool _logToCef,
bool _logToCloud,
bool _logToContainerService,
bool _logTolocalTuning,
bool _logToSyslog,
bool _responseBody,
bool _tpDetect,
@ -55,7 +55,7 @@ LogTriggerSection::LogTriggerSection(
logToAgent(_logToAgent),
logToCef(_logToCef),
logToCloud(_logToCloud),
logToContainerService(_logToContainerService),
logTolocalTuning(_logTolocalTuning),
logToSyslog(_logToSyslog),
responseBody(_responseBody),
tpDetect(_tpDetect),
@ -101,7 +101,7 @@ LogTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
cereal::make_nvp("logToAgent", logToAgent),
cereal::make_nvp("logToCef", logToCef),
cereal::make_nvp("logToCloud", logToCloud),
cereal::make_nvp("logToContainerService", logToContainerService),
cereal::make_nvp("logTolocalTuning", logTolocalTuning),
cereal::make_nvp("logToSyslog", logToSyslog),
cereal::make_nvp("responseBody", responseBody),
cereal::make_nvp("responseCode", false),
@ -393,12 +393,16 @@ AppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
} else {
cloud = false;
}
auto mode = Singleton::Consume<I_AgentDetails>::by<AppsecTriggerLogDestination>()->getOrchestrationMode();
auto env_type = Singleton::Consume<I_EnvDetails>::by<AppsecTriggerLogDestination>()->getEnvType();
bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S);
// BC try load previous name. TODO: update CRD
parseAppsecJSONKey<bool>("k8s-service", container_service, archive_in, k8s_service_default);
parseAppsecJSONKey<bool>("container-service", container_service, archive_in, container_service);
// check ENV VAR LOCAL_TUNING_ENABLED
char * tuning_enabled = getenv("LOCAL_TUNING_ENABLED");
if (tuning_enabled != NULL) {
for (unsigned int i = 0; i < strlen(tuning_enabled); i++) {
tuning_enabled[i] = tolower(tuning_enabled[i]);
}
container_service = string(tuning_enabled) == "true";
} else {
container_service = false;
}
StdoutLogging stdout_log;
parseAppsecJSONKey<StdoutLogging>("stdout", stdout_log, archive_in);

View File

@ -60,20 +60,16 @@ checkSAMLPortal(const string &command_output)
Maybe<string>
checkPepIdaIdnStatus(const string &command_output)
{
if (command_output.find("nac_pep_scaled_sharing_enabled = 1") != string::npos) {
if (command_output.find("nac_pep_identity_next_enabled = 1") != string::npos) {
return string("true");
}
return string("false");
}
Maybe<string>
getIDAGaiaPackages(const string &command_output)
getRequiredNanoServices(const string &command_output)
{
string result = "idaSaml_gaia;idaIdn_gaia;idaIdnBg_gaia;";
if (command_output.find("nac_pep_scaled_sharing_enabled = 1") != string::npos) {
result += "agentIntelligenceService_gaia;";
}
return result;
return command_output;
}
Maybe<string>
@ -191,26 +187,44 @@ getMgmtObjAttr(shared_ptr<istream> file_stream, const string &attr)
}
Maybe<string>
getMgmtObjUid(shared_ptr<istream> file_stream)
getMgmtObjUid(const string &command_output)
{
if (!command_output.empty()) {
return command_output;
}
static const string obj_path = (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myown.C";
auto file_stream = std::make_shared<std::ifstream>(obj_path);
if (!file_stream->is_open()) {
return genError("Failed to open the object file");
}
return getMgmtObjAttr(file_stream, "uuid ");
}
Maybe<string>
getMgmtObjName(shared_ptr<istream> file_stream)
getMgmtObjName(const string &command_output)
{
if (!command_output.empty()) {
return command_output;
}
static const string obj_path = (getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myown.C";
auto file_stream = std::make_shared<std::ifstream>(obj_path);
if (!file_stream->is_open()) {
return genError("Failed to open the object file");
}
return getMgmtObjAttr(file_stream, "name ");
}
Maybe<string>
getGWHardware(const string &command_output)
getHardware(const string &command_output)
{
if (!command_output.empty()) {
if (command_output == "software") return string("Open server");
if (command_output == "Maestro Gateway") return string("Maestro");
return string(command_output);
}
return genError("GW Hardware was not found");
return genError("Hardware was not found");
}
Maybe<string>

View File

@ -42,13 +42,29 @@ SHELL_PRE_CMD("gunzip local.cfg", "gunzip -c $FWDIR/state/local/FW1/local.cfg.gz
#ifdef SHELL_CMD_HANDLER
#if defined(gaia) || defined(smb)
SHELL_CMD_HANDLER("cpProductIntegrationMgmtObjectType", "cpprod_util CPPROD_IsMgmtMachine", getMgmtObjType)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtObjectUid",
"mgmt_cli --format json -r true show-session | jq -r '.[\"connected-server\"].uid'",
getMgmtObjUid
)
SHELL_CMD_HANDLER("prerequisitesForHorizonTelemetry",
"FS_PATH=<FILESYSTEM-PREFIX>; [ -f ${FS_PATH}/cp-nano-horizon-telemetry-prerequisites.log ] "
"&& head -1 ${FS_PATH}/cp-nano-horizon-telemetry-prerequisites.log || echo ''",
checkIsInstallHorizonTelemetrySucceeded)
SHELL_CMD_HANDLER("QUID", "[ -d /opt/CPquid ] "
SHELL_CMD_HANDLER("GLOBAL_QUID", "[ -d /opt/CPquid ] "
"&& python3 /opt/CPquid/Quid_Api.py -i /opt/CPotelcol/quid_api/get_global_id.json | jq -r .message || echo ''",
getQUID)
SHELL_CMD_HANDLER("QUID", "FS_PATH=<FILESYSTEM-PREFIX>;"
"VS_ID=$(echo \"${FS_PATH}\" | grep -o -E \"vs[0-9]+\" | grep -o -E \"[0-9]+\");"
"[ -z \"${VS_ID}\" ] && "
"(python3 /opt/CPquid/Quid_Api.py -i /opt/CPotelcol/quid_api/get_global_id.json | jq -r .message || echo '');"
"[ -n \"${VS_ID}\" ] && "
"(sed \"s|###VS_ID###|${VS_ID}|g\" /opt/CPotelcol/quid_api/get_vs_quid.json"
" > /opt/CPotelcol/quid_api/get_vs_quid.json.${VS_ID}); "
"[ -n \"${VS_ID}\" ] && [ -f /opt/CPotelcol/quid_api/get_vs_quid.json.${VS_ID} ] && "
"(python3 /opt/CPquid/Quid_Api.py -i "
"/opt/CPotelcol/quid_api/get_vs_quid.json.${VS_ID} | jq -r .message[0].QUID || echo '');",
getQUID)
SHELL_CMD_HANDLER("SMO_QUID", "[ -d /opt/CPquid ] "
"&& python3 /opt/CPquid/Quid_Api.py -i /opt/CPotelcol/quid_api/get_smo_quid.json | jq -r .message || echo ''",
getQUID)
@ -102,8 +118,13 @@ SHELL_CMD_HANDLER(
SHELL_CMD_HANDLER("hasSAMLSupportedBlade", "enabled_blades", checkSAMLSupportedBlade)
SHELL_CMD_HANDLER("hasIDABlade", "enabled_blades", checkIDABlade)
SHELL_CMD_HANDLER("hasSAMLPortal", "mpclient status nac", checkSAMLPortal)
SHELL_CMD_HANDLER("hasIdaIdnEnabled", "fw ctl get int nac_pep_scaled_sharing_enabled", checkPepIdaIdnStatus)
SHELL_CMD_HANDLER("requiredNanoServices", "fw ctl get int nac_pep_scaled_sharing_enabled", getIDAGaiaPackages)
SHELL_CMD_HANDLER("hasIdaIdnEnabled", "fw ctl get int nac_pep_identity_next_enabled", checkPepIdaIdnStatus)
SHELL_CMD_HANDLER("requiredNanoServices", "echo 'idaSaml_gaia;idaIdn_gaia;'", getRequiredNanoServices)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtObjectName",
"mgmt_cli --format json -r true show-session | jq -r '.[\"connected-server\"].name'",
getMgmtObjName
)
SHELL_CMD_HANDLER(
"cpProductIntegrationMgmtParentObjectName",
"cat $FWDIR/database/myself_objects.C "
@ -118,8 +139,8 @@ SHELL_CMD_HANDLER(
)
SHELL_CMD_HANDLER(
"Hardware",
"cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:appliance_type/ {print $3}' | head -n 1",
getGWHardware
"cat $FWDIR/database/myself_objects.C | awk -F '[:()]' '/:appliance_type/ {print $3}' | head -n 1 | sed 's/\"//g'",
getHardware
)
SHELL_CMD_HANDLER(
"Application Control",
@ -219,6 +240,7 @@ SHELL_CMD_HANDLER(
SHELL_CMD_OUTPUT("kernel_version", "uname -r")
SHELL_CMD_OUTPUT("helloWorld", "cat /tmp/agentHelloWorld 2>/dev/null")
SHELL_CMD_OUTPUT("report_timestamp", "date -u +\%s")
#endif // SHELL_CMD_OUTPUT
@ -227,17 +249,11 @@ SHELL_CMD_OUTPUT("helloWorld", "cat /tmp/agentHelloWorld 2>/dev/null")
#ifdef FILE_CONTENT_HANDLER
#if defined(gaia)
FILE_CONTENT_HANDLER(
"hasIdpConfigured",
(getenv("SAMLPORTAL_HOME") ? string(getenv("SAMLPORTAL_HOME")) : "") + "/phpincs/spPortal/idpPolicy.xml",
checkIDP
)
FILE_CONTENT_HANDLER(
"cpProductIntegrationMgmtObjectName",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myown.C",
getMgmtObjName
)
#endif //gaia
#if defined(alpine)
@ -245,11 +261,6 @@ FILE_CONTENT_HANDLER("alpine_tag", "/usr/share/build/cp-alpine-tag", getCPAlpine
#endif // alpine
#if defined(gaia) || defined(smb)
FILE_CONTENT_HANDLER("os_release", "/etc/cp-release", getOsRelease)
FILE_CONTENT_HANDLER(
"cpProductIntegrationMgmtObjectUid",
(getenv("FWDIR") ? string(getenv("FWDIR")) : "") + "/database/myown.C",
getMgmtObjUid
)
#else // !(gaia || smb)
FILE_CONTENT_HANDLER("os_release", "/etc/os-release", getOsRelease)
#endif // gaia || smb

View File

@ -40,6 +40,8 @@ public:
i_mainloop = Singleton::Consume<I_MainLoop>::by<HealthChecker>();
i_socket = Singleton::Consume<I_Socket>::by<HealthChecker>();
i_orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<HealthChecker>();
i_service_controller = Singleton::Consume<I_ServiceController>::by<HealthChecker>();
initConfig();
initServerSocket();
@ -270,18 +272,17 @@ private:
}
if (NGEN::Filesystem::exists(rpm_full_load_path)) {
dbgTrace(D_HEALTH_CHECK) << rpm_full_load_path << " exists, returning healthy status";
return HealthCheckStatus::HEALTHY;
dbgTrace(D_HEALTH_CHECK) << "RPM is fully loaded";
return i_service_controller->getServicesPolicyStatus()
? HealthCheckStatus::HEALTHY
: HealthCheckStatus::UNHEALTHY;
}
if (NGEN::Filesystem::exists(rpm_partial_load_path)) {
dbgTrace(D_HEALTH_CHECK) << rpm_partial_load_path << " exists, returning degraded status";
return HealthCheckStatus::DEGRADED;
}
if (!NGEN::Filesystem::exists(first_rpm_policy_load_path)) {
dbgTrace(D_HEALTH_CHECK) << "Could not load latest RPM policy, returning degraded status";
return HealthCheckStatus::DEGRADED;
if (NGEN::Filesystem::exists(rpm_partial_load_path) || !NGEN::Filesystem::exists(first_rpm_policy_load_path)) {
dbgTrace(D_HEALTH_CHECK) << "RPM is partially loaded";
return i_service_controller->getServicesPolicyStatus()
? HealthCheckStatus::DEGRADED
: HealthCheckStatus::UNHEALTHY;
}
dbgTrace(D_HEALTH_CHECK) << "RPM is not loaded, returning unhealthy status";
@ -442,6 +443,7 @@ private:
I_Socket *i_socket = nullptr;
I_Health_Check_Manager *i_health_check_manager = nullptr;
I_OrchestrationStatus *i_orchestration_status = nullptr;
I_ServiceController *i_service_controller = nullptr;
};
HealthChecker::HealthChecker() : Component("HealthChecker"), pimpl(make_unique<Impl>()) {}

View File

@ -9,6 +9,7 @@
#include "mock/mock_shell_cmd.h"
#include "mock/mock_orchestration_status.h"
#include "health_check_manager.h"
#include "mock/mock_service_controller.h"
#include "config.h"
#include "config_component.h"
@ -76,6 +77,7 @@ public:
I_MainLoop::Routine handle_probe_routine;
HealthCheckManager health_check_manager;
I_Health_Check_Manager *i_health_check_manager;
StrictMock<MockServiceController> mock_service_controller;
};
TEST_F(HealthCheckerTest, empty)
@ -342,3 +344,58 @@ TEST_F(HealthCheckerTest, FailedHealthCheck)
connection_handler_routine();
setConfiguration(false, "Health Check", "Probe enabled");
}
TEST_F(HealthCheckerTest, StandaloneHealthCheck)
{
setenv("DOCKER_RPM_ENABLED", "true", 1);
string ip = "1.2.3.4";
setConfiguration(ip, "Health Check", "Probe IP");
uint port = 11600;
setConfiguration(port, "Health Check", "Probe port");
NGEN::Filesystem::touchFile("/tmp/wd.all_running");
NGEN::Filesystem::touchFile("/tmp/rpm_full_load");
auto on_exit = make_scope_exit(
[]() {
NGEN::Filesystem::deleteFile("/tmp/wd.all_running");
NGEN::Filesystem::deleteFile("/tmp/rpm_full_load");
}
);
const string policy_version = "1";
EXPECT_CALL(mock_orchestration_status, getPolicyVersion()).WillRepeatedly(ReturnRef(policy_version));
EXPECT_CALL(mock_service_controller, getServicesPolicyStatus()).WillRepeatedly(Return(true));
EXPECT_CALL(
mock_mainloop,
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, _, false)
).WillOnce(DoAll(SaveArg<1>(&handle_probe_routine), Return(0)));
EXPECT_CALL(
mock_socket,
genSocket(I_Socket::SocketType::TCP, false, true, _)
).WillRepeatedly(Return(1));
EXPECT_CALL(
mock_mainloop,
addFileRoutine(I_MainLoop::RoutineType::System, _, _, _, true)
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
EXPECT_CALL(
mock_mainloop,
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, "Health check probe connection handler", true)
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
int socket = 1;
EXPECT_CALL(mock_socket, acceptSocket(1, false, ip)).WillOnce(Return(socket));
EXPECT_CALL(mock_mainloop, getCurrentRoutineId()).WillRepeatedly(Return(0));
EXPECT_CALL(mock_socket, receiveData(_, 1, false)).WillOnce(Return(vector<char>()));
EXPECT_CALL(mock_socket, writeData(_, response_buffer)).WillOnce(Return(true));
EXPECT_CALL(mock_socket, closeSocket(socket)).Times(2);
health_checker.init();
handle_probe_routine();
connection_handler_routine();
connection_handler_routine();
}

View File

@ -266,7 +266,9 @@ private:
case OrchestrationStatusFieldType::COUNT : return "Count";
}
dbgAssert(false) << "Trying to convert unknown orchestration status field to string.";
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "orchestration health")
<< "Trying to convert unknown orchestration status field to string.";
return "";
}
@ -280,7 +282,9 @@ private:
case UpdatesProcessResult::DEGRADED : return HealthCheckStatus::DEGRADED;
}
dbgAssert(false) << "Trying to convert unknown update process result field to health check status.";
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "orchestration health")
<< "Trying to convert unknown update process result field to health check status.";
return HealthCheckStatus::IGNORED;
}

View File

@ -40,6 +40,8 @@ public:
MOCK_CONST_METHOD0(getPolicyVersions, const std::string &());
MOCK_CONST_METHOD0(getServicesPolicyStatus, bool());
MOCK_METHOD6(
updateServiceConfiguration,
Maybe<void>(

View File

@ -429,14 +429,16 @@ public:
status.insertServiceSetting(service_name, path);
return;
case OrchestrationStatusConfigType::MANIFEST:
dbgAssert(false) << "Manifest is not a service configuration file type";
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "sesrvice configuration")
<< "Manifest is not a service configuration file type";
break;
case OrchestrationStatusConfigType::DATA:
return;
case OrchestrationStatusConfigType::COUNT:
break;
}
dbgAssert(false) << "Unknown configuration file type";
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "sesrvice configuration") << "Unknown configuration file type";
}
void

View File

@ -43,7 +43,10 @@ operator<<(ostream &os, const URLProtocol &protocol)
return os << "file://";
}
default: {
dbgAssert(false) << "Unsupported protocol " << static_cast<unsigned int>(protocol);
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "fog communication")
<< "Unsupported protocol "
<< static_cast<unsigned int>(protocol);
return os;
}
}
@ -91,7 +94,10 @@ URLParser::parseURL(const string &url)
return;
}
default: {
dbgAssert(false) << "URL protocol is not supported. Protocol: " << static_cast<unsigned int>(protocol);
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "fog communication")
<< "URL protocol is not supported. Protocol: "
<< static_cast<unsigned int>(protocol);
return;
}
}

View File

@ -1631,6 +1631,7 @@ private:
string server_name = getAttribute("registered-server", "registered_server");
auto server = TagAndEnumManagement::convertStringToTag(server_name);
if (server_name == "'SWAG'") server = Tags::WEB_SERVER_SWAG;
if (server.ok()) tags.insert(*server);
if (getAttribute("no-setting", "CROWDSEC_ENABLED") == "true") tags.insert(Tags::CROWDSEC);
@ -1652,6 +1653,8 @@ private:
tags
);
if (server_name != "") registration_report.addToOrigin(LogField("eventCategory", server_name));
auto email = getAttribute("email-address", "user_email");
if (email != "") registration_report << LogField("userDefinedId", email);
@ -1694,9 +1697,11 @@ private:
auto temp_ext = getConfigurationWithDefault<string>("_temp", "orchestration", "Temp file extension");
dbgAssert(i_orchestration_tools->doesFileExist(backup_installation_file))
<< AlertInfo(AlertTeam::CORE, "orchestration backup")
<< "There is no backup installation package";
dbgAssert(i_orchestration_tools->copyFile(backup_installation_file, current_installation_file))
<< AlertInfo(AlertTeam::CORE, "orchestration backup")
<< "Failed to copy backup installation package";
// Copy the backup manifest file to the default manifest file path.
@ -1713,8 +1718,10 @@ private:
auto package_handler = Singleton::Consume<I_PackageHandler>::by<OrchestrationComp>();
// Install the backup orchestration service installation package.
dbgAssert(package_handler->preInstallPackage(service_name, current_installation_file))
<< AlertInfo(AlertTeam::CORE, "orchestration backup")
<< "Failed to restore from backup, pre install test failed";
dbgAssert(package_handler->installPackage(service_name, current_installation_file, true))
<< AlertInfo(AlertTeam::CORE, "orchestration backup")
<< "Failed to restore from backup, installation failed";
}
// LCOV_EXCL_STOP

View File

@ -386,7 +386,10 @@ OrchestrationTools::Impl::calculateChecksum(Package::ChecksumTypes checksum_type
return genError("Error while reading file " + path + ", " + e.what());
}
dbgAssert(false) << "Checksum type is not supported. Checksum type: " << static_cast<unsigned int>(checksum_type);
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "service configuration")
<< "Checksum type is not supported. Checksum type: "
<< static_cast<unsigned int>(checksum_type);
return genError("Unsupported checksum type");
}

View File

@ -141,7 +141,10 @@ packageHandlerActionsToString(PackageHandlerActions action)
}
}
dbgAssert(false) << "Package handler action is not supported. Action: " << static_cast<unsigned int>(action);
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "service configuration")
<< "Package handler action is not supported. Action: "
<< static_cast<unsigned int>(action);
return string();
}

View File

@ -71,7 +71,7 @@ public:
UpdatesConfigType::GENERAL,
UpdatesFailureReason::SERVISE_CONFIGURATION,
string(service_name.get() + ", ID: " + to_string(id.get())),
(error_message.isActive() ? " Error: " + error_message.get() : "")
(error_message.isActive() ? " " + error_message.get() : "")
).notify();
dbgError(D_SERVICE_CONTROLLER)
<< "Request for service reconfiguration failed to complete. ID: "
@ -327,6 +327,8 @@ public:
set<string> && moveChangedPolicies() override;
bool getServicesPolicyStatus() const override;
private:
void cleanUpVirtualFiles();
@ -365,6 +367,7 @@ private:
map<int, string> services_reconf_ids;
string filesystem_prefix;
bool is_multi_tenant_env = false;
bool total_services_status = false;
set<string> changed_policy_files;
ServiceDetails orchestration_service_details;
@ -459,6 +462,12 @@ ServiceController::Impl::moveChangedPolicies()
return move(changed_policy_files);
}
bool
ServiceController::Impl::getServicesPolicyStatus() const
{
return total_services_status;
}
void
ServiceController::Impl::init()
{
@ -960,6 +969,8 @@ ServiceController::Impl::sendSignalForServices(
const string &policy_version_to_update)
{
dbgFlow(D_SERVICE_CONTROLLER) << "Policy version to update: " << policy_version_to_update;
total_services_status = false;
for (auto &service_id : nano_services_to_update) {
auto nano_service = registered_services.find(service_id);
if (nano_service == registered_services.end()) {
@ -1002,6 +1013,7 @@ ServiceController::Impl::sendSignalForServices(
<< "The reconfiguration was successfully completed for all the services";
services_reconf_status.clear();
services_reconf_names.clear();
total_services_status = true;
return Maybe<void>();
}
case ReconfStatus::IN_PROGRESS: {

View File

@ -790,6 +790,7 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations)
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, general_settings_path).ok());
EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value);
EXPECT_EQ(i_service_controller->getServicesPolicyStatus(), true);
}
TEST_F(ServiceControllerTest, backup)

View File

@ -467,7 +467,10 @@ getDeplymentType()
case EnvType::COUNT: break;
}
dbgAssert(false) << "Failed to get a legitimate deplyment type: " << static_cast<uint>(deplyment_type);
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "fog communication")
<< "Failed to get a legitimate deplyment type: "
<< static_cast<uint>(deplyment_type);
return "Embedded";
}

View File

@ -18,6 +18,7 @@
#include "debug.h"
#include "log_generator.h"
#include "service_health_update_event.h"
using namespace std;
@ -34,6 +35,7 @@ UpdatesProcessReporter::upon(const UpdatesProcessEvent &event)
if (event.getResult() == UpdatesProcessResult::SUCCESS && reports.empty()) {
dbgTrace(D_UPDATES_PROCESS_REPORTER) << "Update proccess finished successfully";
report_failure_count_map.erase(version);
ServiceHealthUpdateEvent().notify();
return;
}
if (report_failure_count_map.find(version) == report_failure_count_map.end()) {
@ -62,6 +64,7 @@ UpdatesProcessReporter::upon(const UpdatesProcessEvent &event)
reports.emplace_back(
UpdatesProcessReport(event.getResult(), event.getType(), event.getReason(), event.parseDescription())
);
ServiceHealthUpdateEvent(convertUpdatesConfigTypeToStr(event.getType()), event.parseDescription()).notify();
}
void

View File

@ -211,6 +211,8 @@ public:
for (const auto &rule : rate_limit_config.getRateLimitRules()) {
string full_rule_uri = application_uri + rule.getRateLimitUri();
transform(full_rule_uri.begin(), full_rule_uri.end(),
full_rule_uri.begin(), [](unsigned char c) { return std::tolower(c); });
int full_rule_uri_length = full_rule_uri.length();
dbgTrace(D_RATE_LIMIT)

View File

@ -390,6 +390,38 @@ DeepParser::onKv(const char *k, size_t k_len, const char *v, size_t v_len, int f
}
}
if (flags & BUFFERED_RECEIVER_F_FIRST && offset < 0 && valueStats.hasPercent &&
m_key.first().size() == 6 && m_key.first() == "cookie") {
dbgTrace(D_WAAP_DEEP_PARSER)
<< "1st pass of createInternalParser() failed. "
<< "Will try to decode percent-encoded data and repeate search for parser";
orig_val.erase(unquote_plus(orig_val.begin(), orig_val.end()), orig_val.end());
cur_val_html_escaped = orig_val;
cur_val_html_escaped.erase(
escape_html(cur_val_html_escaped.begin(), cur_val_html_escaped.end()), cur_val_html_escaped.end()
);
offset = createInternalParser(
k,
k_len,
orig_val,
valueStats,
isBodyPayload,
isRefererPayload,
isRefererParamPayload,
isUrlPayload,
isUrlParamPayload,
flags,
parser_depth,
base64BinaryFileType
);
if (offset >= 0) {
dbgTrace(D_WAAP_DEEP_PARSER) << "2nd pass of createInternalParser succeeded. Update values and proceed";
ValueStatsAnalyzer valueStatsUpdated(cur_val_html_escaped);
cur_val.erase(unquote_plus(cur_val.begin(), cur_val.end()), cur_val.end());
Waap::Util::decodeUtf16Value(valueStatsUpdated, cur_val);
}
}
// If there's a parser in parsers stack, push the value to the top parser
if (!m_parsersDeque.empty()
&& offset >= 0
@ -1183,6 +1215,7 @@ DeepParser::createInternalParser(
offset = 0;
}
}
bool isCockiePapameter = m_key.depth() == 2 && m_key.first().size() == 6 && m_key.first() == "cookie";
if (offset < 0) {
if (isPipesType) {
dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse pipes, positional: " << isKeyValDelimited;
@ -1279,7 +1312,7 @@ DeepParser::createInternalParser(
);
} else if (!Waap::Util::testUrlBareUtf8Evasion(cur_val)) {
dbgTrace(D_WAAP_DEEP_PARSER) << "!Waap::Util::testUrlBareUtf8Evasion(cur_val)";
if (!valueStats.hasSpace
if ((!valueStats.hasSpace || (valueStats.hasSpace && isCockiePapameter))
&& valueStats.hasCharAmpersand
&& valueStats.hasTwoCharsEqual
&& !isBinaryData()
@ -1305,7 +1338,7 @@ DeepParser::createInternalParser(
}
} else if (!Waap::Util::testUrlBareUtf8Evasion(cur_val)) {
dbgTrace(D_WAAP_DEEP_PARSER) << "!Waap::Util::testUrlBareUtf8Evasion(cur_val)";
if (!valueStats.hasSpace
if ((!valueStats.hasSpace || (valueStats.hasSpace && isCockiePapameter))
&& valueStats.hasCharAmpersand
&& valueStats.hasTwoCharsEqual
&& !isBinaryData()

View File

@ -103,6 +103,9 @@ ParserUrlEncode::push(const char *buf, size_t len)
}
case s_key_start: {
dbgTrace(D_WAAP_PARSER_URLENCODE) << "ParserUrlEncode::push(): s_key_start";
if (isspace(c)){
break;
}
mark = i;
m_state = s_key;
@ -112,12 +115,6 @@ ParserUrlEncode::push(const char *buf, size_t len)
case s_key: {
dbgTrace(D_WAAP_PARSER_URLENCODE) << "ParserUrlEncode::push(): s_key";
// skip leading spaces in the key
if (isspace(c)) {
m_state = s_key_start; // skip the space character without including it in the output
break;
}
if (c == '%' && should_decode_percent) {
if (i - mark > 0) {
if (m_receiver.onKey(buf + mark, i - mark) != 0) {

View File

@ -48,7 +48,7 @@ public:
if (m_tag != "sourceip" && m_tag != "sourceidentifier" && m_tag != "url" && m_tag != "hostname" &&
m_tag != "keyword" && m_tag != "paramname" && m_tag != "paramvalue" && m_tag != "paramlocation" &&
m_tag != "responsebody" && m_tag != "headername" && m_tag != "headervalue" ) {
m_tag != "responsebody" && m_tag != "headername" && m_tag != "headervalue" && m_tag != "method") {
m_isValid = false;
dbgDebug(D_WAAP_OVERRIDE) << "Invalid override tag: " << m_tag;
}

View File

@ -51,7 +51,10 @@ bool WaapOverrideFunctor::operator()(const std::string& tag, const boost::regex&
std::string tagLower = tag;
std::transform(tagLower.begin(), tagLower.end(), tagLower.begin(), ::tolower);
try {
if (tagLower == "url") {
if (tagLower == "method") {
return NGEN::Regex::regexMatch(__FILE__, __LINE__, waf2Transaction.getMethod().c_str(), what, rx);
}
else if (tagLower == "url") {
return NGEN::Regex::regexMatch(__FILE__, __LINE__, waf2Transaction.getUriStr().c_str(), what, rx);
}
else if (tagLower == "hostname") {

View File

@ -95,7 +95,9 @@ ValueStatsAnalyzer::ValueStatsAnalyzer(const std::string &cur_val)
canSplitPipe(true),
hasSpace(false),
isUrlEncoded(false),
hasCharLess(false)
hasCharLess(false),
hasDoubleQuote(false),
hasPercent(false)
{
unsigned int zerosSeq[2] = {0};
bool lastNul = false; // whether last processed character was ASCII NUL
@ -146,6 +148,9 @@ ValueStatsAnalyzer::ValueStatsAnalyzer(const std::string &cur_val)
case '\"':
hasDoubleQuote = true;
break;
case '%':
hasPercent = true;
break;
}
if (isspace(ch)) {
@ -270,4 +275,6 @@ ValueStatsAnalyzer::ValueStatsAnalyzer(const std::string &cur_val)
textual +=(hasCharLess ? "true" : "false");
textual.append("\nhasDoubleQuote = ");
textual +=(hasDoubleQuote ? "true" : "false");
textual.append("\nhasPercent = ");
textual +=(hasPercent ? "true" : "false");
}

View File

@ -36,6 +36,7 @@ struct ValueStatsAnalyzer
bool isUrlEncoded;
bool hasCharLess;
bool hasDoubleQuote;
bool hasPercent;
std::string textual;
};

View File

@ -867,7 +867,7 @@ void Waf2Transaction::parseCookie(const char* value, int value_len)
if (value_len > 0) {
dbgTrace(D_WAAP_HEADERS) << "[transaction:" << this << "] scanning the cookie value";
m_deepParser.m_key.push("cookie", 6);
ParserUrlEncode cookieValueParser(m_deepParserReceiver, 0, ';');
ParserUrlEncode cookieValueParser(m_deepParserReceiver, 0, ';', false);
cookieValueParser.push(value, value_len);
cookieValueParser.finish();
m_deepParser.m_key.pop("cookie");
@ -1077,6 +1077,9 @@ void Waf2Transaction::add_request_hdr(const char* name, int name_len, const char
std::string header_name(name, name_len);
boost::algorithm::to_lower(header_name);
hdrs_map[header_name] = std::string(value, value_len);
if (header_name == "host") {
m_hostStr = hdrs_map[header_name];
}
}
void Waf2Transaction::end_request_hdrs() {

View File

@ -117,7 +117,7 @@ WaapComponent::Impl::fini()
std::string
WaapComponent::Impl::getListenerName() const
{
return "waap application";
return WAAP_APPLICATION_NAME;
}
// Start request (called before headers arrive). However, the method and URL path is known at this stage.

View File

@ -4,3 +4,4 @@ add_subdirectory(http_transaction_data)
add_subdirectory(ip_utilities)
add_subdirectory(keywords)
add_subdirectory(pm)
add_subdirectory(service_health_status)

View File

@ -173,7 +173,7 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
setTriggersFlag("webUrlQuery", archive_in, WebLogFields::webUrlQuery, log_web_fields);
setTriggersFlag("logToAgent", archive_in, ReportIS::StreamType::JSON_LOG_FILE, active_streams);
setTriggersFlag("logToCloud", archive_in, ReportIS::StreamType::JSON_FOG, active_streams);
setTriggersFlag("logToContainerService", archive_in, ReportIS::StreamType::JSON_CONTAINER_SVC, active_streams);
setTriggersFlag("logTolocalTuning", archive_in, ReportIS::StreamType::JSON_CONTAINER_SVC, active_streams);
setTriggersFlag("logToSyslog", archive_in, ReportIS::StreamType::SYSLOG, active_streams);
setTriggersFlag("logToCef", archive_in, ReportIS::StreamType::CEF, active_streams);
setTriggersFlag("acAllow", archive_in, SecurityType::AccessControl, should_log_on_detect);

View File

@ -301,7 +301,7 @@ ConvertToIpAddress(const IPAddr &addr) {
break;
}
default:
dbgAssert(false) << "Unsupported IP type";
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "ip utilities") << "Unsupported IP type";
}
return address;
}

View File

@ -74,7 +74,9 @@ private:
uint
moveOnNoMatch(uint offset_from_end, unsigned char first_unmatched_byte) const
{
dbgAssert(shift.size() > offset_from_end) << "Shift table of the 'data' keyword is shorter than the offset";
dbgAssert(shift.size() > offset_from_end)
<< AlertInfo(AlertTeam::CORE, "keywords")
<< "Shift table of the 'data' keyword is shorter than the offset";
uint skip_size;
if (skip[first_unmatched_byte]>offset_from_end) {
@ -350,7 +352,9 @@ DataKeyword::bytesMatched(const Buffer &buf, uint offset) const
MatchStatus
DataKeyword::isMatch(const I_KeywordRuntimeState *prev) const
{
dbgAssert(pattern.size()>0) << "Trying to run on an uninitialized keyword data";
dbgAssert(pattern.size()>0)
<< AlertInfo(AlertTeam::CORE, "keywords")
<< "Trying to run on an uninitialized keyword data";
dbgDebug(D_KEYWORD) << "Searching for " << dumpHex(pattern);

View File

@ -143,7 +143,7 @@ jumpKeyword::getStartOffset(uint buf_size, const I_KeywordRuntimeState *prev) co
return prev->getOffset(ctx);
}
}
dbgAssert(false) << "Invalid jumping 'from' parameter";
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "keywords") << "Invalid jumping 'from' parameter";
return 0;
}

View File

@ -90,7 +90,7 @@ SentinelRuntimeState::getOffset(const std::string &) const
uint
SentinelRuntimeState::getVariable(uint var_id) const
{
dbgAssert(false) << "Could not find the variable ID: " << var_id;
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "keywords") << "Could not find the variable ID: " << var_id;
return 0;
}
// LCOV_EXCL_STOP

View File

@ -297,7 +297,9 @@ PCREKeyword::getStartOffsetAndLength(uint buf_size, const I_KeywordRuntimeState
MatchStatus
PCREKeyword::isMatch(const I_KeywordRuntimeState *prev) const
{
dbgAssert(pcre_machine!=nullptr) << "Trying to run on an uninitialized keyword 'pcre'";
dbgAssert(pcre_machine!=nullptr)
<< AlertInfo(AlertTeam::CORE, "keywords")
<< "Trying to run on an uninitialized keyword 'pcre'";
auto part = Singleton::Consume<I_Environment>::by<KeywordComp>()->get<Buffer>(static_cast<string>(ctx));

View File

@ -250,7 +250,9 @@ ComparisonAttr::operator()(int first_val, int second_val) const
return first_val >= second_val;
}
}
dbgAssert(false) << "ComparisonAttr::operator found an invalid comparison operator";
dbgAssert(false)
<< AlertInfo(AlertTeam::CORE, "keywords")
<< "ComparisonAttr::operator found an invalid comparison operator";
return false;
}

View File

@ -131,7 +131,7 @@ StateopKeyword::isMatch(const I_KeywordRuntimeState *prev) const
if (table->hasState<KeywordStateop>()) table->getState<KeywordStateop>().removeVariable(var_name);
return runNext(prev);
} else {
dbgAssert(false) << "Impossible 'stateop' keyword without operation";
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "keywords") << "Impossible 'stateop' keyword without operation";
}
// If there was no matches and the keyword is effected by other keywords, then we know that the rule won't match

View File

@ -80,7 +80,7 @@ kiss_pmglob_string_s::kiss_pmglob_string_s(const char *buffer, size_t size, int
kiss_pmglob_string_s::kiss_pmglob_string_s(const u_char *buffer, size_t size, int _pattern_id, u_int _flags)
{
dbgAssert(buffer && size > 0) << "Illegal arguments";
dbgAssert(buffer && size > 0) << AlertInfo(AlertTeam::CORE, "pattern matcher") << "Illegal arguments";
buf.resize(size);
memcpy(buf.data(), buffer, size);
pattern_id = _pattern_id;

View File

@ -430,7 +430,9 @@ kiss_thin_nfa_exec(KissThinNFA *nfa_h, const Buffer& buf, std::vector<std::pair<
{
struct kiss_bnfa_runtime_s bnfa_runtime;
dbgAssert(nfa_h != nullptr) << "kiss_thin_nfa_exec() was called with null handle";
dbgAssert(nfa_h != nullptr)
<< AlertInfo(AlertTeam::CORE, "pattern matcher")
<< "kiss_thin_nfa_exec() was called with null handle";
if (buf.size() == 0) {
return;

View File

@ -105,7 +105,7 @@ PMHook::prepare(const set<PMPattern> &inputs)
set<PMPattern>
PMHook::scanBuf(const Buffer &buf) const
{
dbgAssert(handle != nullptr) << "Unusable Pattern Matcher";
dbgAssert(handle != nullptr) << AlertInfo(AlertTeam::CORE, "pattern matcher") << "Unusable Pattern Matcher";
vector<pair<uint, uint>> pm_matches;
kiss_thin_nfa_exec(handle.get(), buf, pm_matches);
dbgTrace(D_PM) << pm_matches.size() << " raw matches found";
@ -121,7 +121,7 @@ PMHook::scanBuf(const Buffer &buf) const
set<pair<uint, uint>>
PMHook::scanBufWithOffset(const Buffer &buf) const
{
dbgAssert(handle != nullptr) << "Unusable Pattern Matcher";
dbgAssert(handle != nullptr) << AlertInfo(AlertTeam::CORE, "pattern matcher") << "Unusable Pattern Matcher";
vector<pair<uint, uint>> pm_matches;
kiss_thin_nfa_exec(handle.get(), buf, pm_matches);
@ -135,7 +135,7 @@ PMHook::scanBufWithOffset(const Buffer &buf) const
void
PMHook::scanBufWithOffsetLambda(const Buffer &buf, I_PMScan::CBFunction cb) const
{
dbgAssert(handle != nullptr) << "Unusable Pattern Matcher";
dbgAssert(handle != nullptr) << AlertInfo(AlertTeam::CORE, "pattern matcher") << "Unusable Pattern Matcher";
unordered_map<uint, uint> match_counts;
vector<pair<uint, uint>> pm_matches;

View File

@ -0,0 +1,2 @@
add_library(service_health_status service_health_status.cc)
add_subdirectory(service_health_status_ut)

View File

@ -0,0 +1,104 @@
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License");
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "service_health_status.h"
#include <fstream>
#include <string>
#include "debug.h"
#include "rest.h"
#include "customized_cereal_map.h"
#include "service_health_update_event.h"
using namespace std;
USE_DEBUG_FLAG(D_SERVICE_HEALTH_STATUS);
class I_ServiceHealthStatusImpl
{
public:
virtual const map<string, string> & getErrors() const = 0;
protected:
virtual ~I_ServiceHealthStatusImpl() {}
};
class ServiceHealthStatus::Impl
:
public Singleton::Provide<I_ServiceHealthStatusImpl>::SelfInterface,
public Listener<ServiceHealthUpdateEvent>
{
public:
void init();
const map<string, string> & getErrors() const override { return errors_map; }
void upon(const ServiceHealthUpdateEvent &event) override;
private:
map<string, string> errors_map;
};
class ServiceHealthStatusRest
:
public ServerRest,
Singleton::Consume<I_ServiceHealthStatusImpl>
{
using ErrorsMap = map<string, string>;
public:
void
doCall()
{
errors = Singleton::Consume<I_ServiceHealthStatusImpl>::by<ServiceHealthStatusRest>()->getErrors();
healthy = errors.get().empty();
dbgTrace(D_SERVICE_HEALTH_STATUS)
<< "Heath status requested. "
<< (healthy ? "Service is healthy." : "Service is not healthy.");
}
private:
S2C_PARAM(bool, healthy);
S2C_PARAM(ErrorsMap, errors);
};
void
ServiceHealthStatus::Impl::init()
{
if (!Singleton::exists<I_RestApi>()) return;
Singleton::Consume<I_RestApi>::by<ServiceHealthStatus>()->addRestCall<ServiceHealthStatusRest>(
RestAction::SHOW,
"health"
);
registerListener();
}
void
ServiceHealthStatus::Impl::upon(const ServiceHealthUpdateEvent &event)
{
dbgTrace(D_SERVICE_HEALTH_STATUS)
<< "Service health update event. Error: "
<< event.getComponent()
<< " - "
<< event.getError();
if (event.isHealthyUpdate()) {
errors_map.clear();
} else {
errors_map[event.getComponent()] = event.getError();
}
}
ServiceHealthStatus::ServiceHealthStatus() : Component("ServiceHealthStatus"), pimpl(make_unique<Impl>()) {}
ServiceHealthStatus::~ServiceHealthStatus() {}
void ServiceHealthStatus::init() { pimpl->init(); }

View File

@ -0,0 +1,8 @@
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${BOOST_ROOT}/lib)
add_unit_test(
service_health_status_ut
"service_health_status_ut.cc"
"service_health_status;rest;event_is;connkey;mainloop;encryptor;messaging;-lz;metric;-lboost_regex;-lboost_context;-lcrypto;"
)

View File

@ -0,0 +1,73 @@
#include "service_health_status.h"
#include "cptest.h"
#include "environment.h"
#include "config.h"
#include "config_component.h"
#include "debug.h"
#include "connkey.h"
#include "rest.h"
#include "rest_server.h"
#include "mock/mock_rest_api.h"
#include "service_health_update_event.h"
using namespace std;
using namespace testing;
USE_DEBUG_FLAG(D_GEO_DB);
class HealthCheckStatusTest : public Test
{
public:
HealthCheckStatusTest()
{
EXPECT_CALL(mock_rest, mockRestCall(RestAction::SHOW, "health", _))
.WillOnce(WithArg<2>(Invoke(this, &HealthCheckStatusTest::showHealthCheckStatus)));
health_check_status.init();
}
bool
showHealthCheckStatus(const unique_ptr<RestInit> &p)
{
show_health_check_status = p->getRest();
return true;
}
::Environment env;
ConfigComponent config;
ServiceHealthStatus health_check_status;
NiceMock<MockRestApi> mock_rest;
unique_ptr<ServerRest> show_health_check_status;
};
TEST_F(HealthCheckStatusTest, testHealthCheckStatus)
{
ServiceHealthUpdateEvent().notify();
stringstream ss("{}");
Maybe<string> maybe_res = show_health_check_status->performRestCall(ss);
EXPECT_TRUE(maybe_res.ok());
EXPECT_EQ(maybe_res.unpack(),
"{\n"
" \"healthy\": true,\n"
" \"errors\": {}\n"
"}"
);
}
TEST_F(HealthCheckStatusTest, testNotHealthyService)
{
ServiceHealthUpdateEvent("test", "test description").notify();
stringstream ss("{}");
Maybe<string> maybe_res = show_health_check_status->performRestCall(ss);
EXPECT_TRUE(maybe_res.ok());
EXPECT_EQ(maybe_res.unpack(),
"{\n"
" \"healthy\": false,\n"
" \"errors\": {\n"
" \"test\": \"test description\"\n"
" }\n"
"}"
);
}

View File

@ -30,6 +30,7 @@ add_subdirectory(version)
add_subdirectory(tenant_manager)
add_subdirectory(compression)
add_subdirectory(attachments)
add_subdirectory(report_messaging)
add_library(ngen_core SHARED ".")
target_link_libraries(
@ -38,6 +39,7 @@ target_link_libraries(
"table;debug_is;shell_cmd;metric;tenant_manager;messaging;encryptor;time_proxy;singleton;mainloop;environment;logging;report;rest"
"config;intelligence_is_v2;event_is;memory_consumption;connkey"
"instance_awareness;socket_is;agent_details;agent_details_reporter;buffers;cpu;agent_core_utilities"
"report_messaging"
-Wl,-no-whole-archive
)

View File

@ -183,6 +183,8 @@ copyFile(const string &src, const string &dest, bool overide_if_exists, mode_t p
}
dbgTrace(D_INFRA_UTILS) << "Finished attempt to copy file. Res: " << (bytes_copied != -1 ? "Success" : "Error");
close(source_fd);
close(dest_fd);
return bytes_copied != -1;
}
@ -261,6 +263,66 @@ touchFile(const string &path)
return true;
}
bool
copyDirectory(const string &src_dir_path, const string &dst_dir_path)
{
dbgFlow(D_INFRA_UTILS)
<< "Trying to copy directory. Source: "
<< src_dir_path
<< ", Destination: "
<< dst_dir_path;
if (!exists(src_dir_path) || !isDirectory(src_dir_path)) {
dbgDebug(D_INFRA_UTILS) << "Failed to copy directory. Error: source directory does not exist";
return false;
}
if (!exists(dst_dir_path)) {
if (!makeDir(dst_dir_path, 0755)) {
dbgDebug(D_INFRA_UTILS) << "Failed to copy directory. Error: failed to create destination directory";
return false;
}
}
if (!isDirectory(dst_dir_path)) {
dbgDebug(D_INFRA_UTILS) << "Failed to copy directory. Error: destination path is not a directory";
return false;
}
struct dirent *entry = nullptr;
DIR *directory = opendir(src_dir_path.c_str());
if (!directory) {
dbgWarning(D_INFRA_UTILS) << "Fail to open directory. Path: " << src_dir_path;
return false;
}
while ((entry = readdir(directory))) {
string entry_name = entry->d_name;
static const string curr_dir(".");
static const string parent_dir("..");
if (entry_name == curr_dir || entry_name == parent_dir) {
dbgTrace(D_INFRA_UTILS) << "Skipping irrelevant directory entries. Entry name: " << entry_name;
continue;
}
string src_entry_path = src_dir_path + (src_dir_path.back() == '/' ? "" : "/") + entry_name;
string dst_entry_path = dst_dir_path + (dst_dir_path.back() == '/' ? "" : "/") + entry_name;
struct stat statbuf;
if (!stat(src_entry_path.c_str(), &statbuf)) {
if (S_ISDIR(statbuf.st_mode)) {
copyDirectory(src_entry_path, dst_entry_path);
} else {
copyFile(src_entry_path, dst_entry_path, true);
}
}
}
closedir(directory);
return true;
}
string
convertToHumanReadable(uint64_t size_in_bytes)
{

View File

@ -10,6 +10,8 @@
using namespace std;
using namespace testing;
USE_DEBUG_FLAG(D_INFRA_UTILS);
auto contexts = make_pair(std::vector<Context *>(), false);
class AgentCoreUtilUT : public Test
@ -17,6 +19,7 @@ class AgentCoreUtilUT : public Test
public:
AgentCoreUtilUT()
{
Debug::setUnitTestFlag(D_INFRA_UTILS, Debug::DebugLevel::TRACE);
ON_CALL(mock_env, getActiveContexts()).WillByDefault(ReturnPointee(&contexts));
}
@ -123,6 +126,59 @@ TEST_F(AgentCoreUtilUT, isDirectoryTest)
EXPECT_EQ(NGEN::Filesystem::isDirectory("./test"), true);
}
TEST_F(AgentCoreUtilUT, copyDirectoryTest)
{
string sourceDir = cptestFnameInExeDir("sourceDir1");
string destDir = cptestFnameInExeDir("destDir1");
cout << "sourceDir: " << sourceDir << endl;
NGEN::Filesystem::makeDir(sourceDir);
NGEN::Filesystem::makeDir(sourceDir + "/subdir1");
NGEN::Filesystem::makeDir(sourceDir + "/subdir2");
NGEN::Filesystem::makeDir(destDir);
ofstream file_1(sourceDir + "/file1.txt");
ASSERT_TRUE(file_1.is_open());
file_1 << "File 1 content";
file_1.close();
ofstream file_2(sourceDir + "/subdir1/file2.txt");
ASSERT_TRUE(file_2.is_open());
file_2 << "File 2 content";
file_2.close();
ofstream file_3(sourceDir + "/subdir2/file3.txt");
ASSERT_TRUE(file_3.is_open());
file_3 << "File 3 content";
file_3.close();
ASSERT_TRUE(NGEN::Filesystem::copyDirectory(sourceDir, destDir));
EXPECT_TRUE(NGEN::Filesystem::exists(destDir));
EXPECT_TRUE(NGEN::Filesystem::exists(destDir + "/file1.txt"));
EXPECT_TRUE(NGEN::Filesystem::exists(destDir + "/subdir1/file2.txt"));
EXPECT_TRUE(NGEN::Filesystem::exists(destDir + "/subdir2/file3.txt"));
ifstream file1(destDir + "/file1.txt");
string content1((istreambuf_iterator<char>(file1)), istreambuf_iterator<char>());
EXPECT_EQ(content1, "File 1 content");
file1.close();
ifstream file2(destDir + "/subdir1/file2.txt");
string content2((istreambuf_iterator<char>(file2)), istreambuf_iterator<char>());
EXPECT_EQ(content2, "File 2 content");
file2.close();
ifstream file3(destDir + "/subdir2/file3.txt");
string content3((istreambuf_iterator<char>(file3)), istreambuf_iterator<char>());
EXPECT_EQ(content3, "File 3 content");
file3.close();
NGEN::Filesystem::deleteDirectory(sourceDir + "/subdir1", true);
NGEN::Filesystem::deleteDirectory(sourceDir + "/subdir2", true);
NGEN::Filesystem::deleteDirectory(sourceDir, true);
NGEN::Filesystem::deleteDirectory(destDir + "/subdir1", true);
NGEN::Filesystem::deleteDirectory(destDir + "/subdir2", true);
NGEN::Filesystem::deleteDirectory(destDir, true);
}
TEST_F(AgentCoreUtilUT, removeTrailingWhitespacesTest)
{
string str_with_trailing_whitespace = "str_with_trailing_whitespace\n\n\n\r \n\n\r";

View File

@ -27,6 +27,7 @@ using namespace std;
USE_DEBUG_FLAG(D_ORCHESTRATOR);
static const AlertInfo alert(AlertTeam::CORE, "agent details");
const map<string, I_AgentDetails::MachineType> AgentDetails::machineTypes({
{ "Amazon EC2", I_AgentDetails::MachineType::AWS },
@ -381,7 +382,7 @@ AgentDetails::convertProxyProtocolToString(ProxyProtocol proto) const
case ProxyProtocol::HTTP: return "http";
case ProxyProtocol::HTTPS: return "https";
}
dbgAssert(false) << "Unsupported Proxy Protocol " << static_cast<int>(proto);
dbgAssert(false) << alert << "Unsupported Proxy Protocol " << static_cast<int>(proto);
return "";
}
@ -469,7 +470,9 @@ AgentDetails::loadProxyType(ProxyProtocol protocol)
{
dbgFlow(D_ORCHESTRATOR) << "Loading proxy type: " << convertProxyProtocolToString(protocol);
dbgAssert(protocol == ProxyProtocol::HTTP || protocol == ProxyProtocol::HTTPS)
<< "Unsupported Proxy Protocol " << static_cast<int>(protocol);
<< alert
<< "Unsupported Proxy Protocol "
<< static_cast<int>(protocol);
static const map<ProxyProtocol, string> env_var_name = {
{ProxyProtocol::HTTPS, "https_proxy"},

View File

@ -17,6 +17,8 @@
using namespace std;
static const AlertInfo alert(AlertTeam::CORE, "buffer i/s");
Buffer::Buffer(vector<u_char> &&vec)
:
len(vec.size())
@ -142,7 +144,7 @@ Buffer::operator+(const Buffer &other) const
Buffer
Buffer::getSubBuffer(uint start, uint end) const
{
dbgAssert(start<=end && end<=len) << "Buffer::getSubBuffer() returned: Illegal scoping of buffer";
dbgAssert(start<=end && end<=len) << alert << "Buffer::getSubBuffer() returned: Illegal scoping of buffer";
if (start == end) return Buffer();
Buffer res;
@ -176,7 +178,7 @@ Buffer::getSubBuffer(uint start, uint end) const
Maybe<uint>
Buffer::findFirstOf(char ch, uint start) const
{
dbgAssert(start <= len) << "Buffer::findFirstOf() returned: Cannot set a start point after buffer's end";
dbgAssert(start <= len) << alert << "Buffer::findFirstOf() returned: Cannot set a start point after buffer's end";
for (; start < len; ++start) {
if ((*this)[start] == ch) return start;
@ -187,7 +189,7 @@ Buffer::findFirstOf(char ch, uint start) const
Maybe<uint>
Buffer::findFirstOf(const Buffer &buf, uint start) const
{
dbgAssert(start <= len) << "Buffer::findFirstOf() returned: Cannot set a start point after buffer's end";
dbgAssert(start <= len) << alert << "Buffer::findFirstOf() returned: Cannot set a start point after buffer's end";
for (; start + buf.size() <= len; ++start) {
auto sub_buffer = getSubBuffer(start, start + buf.size());
@ -199,7 +201,9 @@ Buffer::findFirstOf(const Buffer &buf, uint start) const
Maybe<uint>
Buffer::findFirstNotOf(char ch, uint start) const
{
dbgAssert(start <= len) << "Buffer::findFirstNotOf() returned: Cannot set a start point after buffer's end";
dbgAssert(start <= len)
<< alert
<< "Buffer::findFirstNotOf() returned: Cannot set a start point after buffer's end";
for (; start < len; ++start) {
if ((*this)[start] != ch) return start;
}
@ -209,7 +213,7 @@ Buffer::findFirstNotOf(char ch, uint start) const
Maybe<uint>
Buffer::findLastOf(char ch, uint start) const
{
dbgAssert(start <= len) << "Buffer::findLastOf() returned: Cannot set a start point after buffer's end";
dbgAssert(start <= len) << alert << "Buffer::findLastOf() returned: Cannot set a start point after buffer's end";
for (; 0 < start; --start) {
if ((*this)[start - 1] == ch) return start - 1;
}
@ -219,7 +223,9 @@ Buffer::findLastOf(char ch, uint start) const
Maybe<uint>
Buffer::findLastNotOf(char ch, uint start) const
{
dbgAssert(start <= len) << "Buffer::findLastNotOf() returned: Cannot set a start point after buffer's end";
dbgAssert(start <= len)
<< alert
<< "Buffer::findLastNotOf() returned: Cannot set a start point after buffer's end";
for (; 0 < start; --start) {
if ((*this)[start - 1] != ch) return start - 1;
}
@ -229,7 +235,7 @@ Buffer::findLastNotOf(char ch, uint start) const
void
Buffer::truncateHead(uint size)
{
dbgAssert(size <= len) << "Cannot set a new start of buffer after the buffer's end";
dbgAssert(size <= len) << alert << "Cannot set a new start of buffer after the buffer's end";
if (size == 0) return;
if (size == len) {
clear();
@ -255,7 +261,7 @@ Buffer::truncateHead(uint size)
void
Buffer::truncateTail(uint size)
{
dbgAssert(size <= len) << "Cannot set a new end of buffer after the buffer's end";
dbgAssert(size <= len) << alert << "Cannot set a new end of buffer after the buffer's end";
if (size == 0) return;
if (size == len) {
clear();
@ -279,14 +285,14 @@ Buffer::truncateTail(uint size)
void
Buffer::keepHead(uint size)
{
dbgAssert(size <= len) << "Cannot set a new end of buffer before the buffer's start";
dbgAssert(size <= len) << alert << "Cannot set a new end of buffer before the buffer's start";
truncateTail(len - size);
}
void
Buffer::keepTail(uint size)
{
dbgAssert(size <= len) << "Cannot set a new start of buffer after the buffer's end";
dbgAssert(size <= len) << alert << "Cannot set a new start of buffer after the buffer's end";
truncateHead(len - size);
}
@ -376,7 +382,7 @@ Buffer::operator[](uint offset) const
}
return fast_path_ptr[offset];
}
dbgAssert(offset < len) << "Buffer::operator returned: attempted an access outside the buffer";
dbgAssert(offset < len) << alert << "Buffer::operator returned: attempted an access outside the buffer";
return *(begin() + offset);
}

View File

@ -67,10 +67,11 @@ Buffer::CharIterator::operator==(const CharIterator &other) const
return (cur_seg == other.cur_seg) && (offset == other.offset);
}
static const AlertInfo alert(AlertTeam::CORE, "buffer i/s");
const u_char &
Buffer::CharIterator::operator*() const
{
dbgAssert(ptr != nullptr) << "Buffer::CharIterator is not pointing to a real value";
dbgAssert(ptr != nullptr) << alert << "Buffer::CharIterator is not pointing to a real value";
return ptr[offset];
}

View File

@ -25,7 +25,10 @@ public:
);
setCompressionDebugFunction(
CompressionUtilsDebugLevel::COMPRESSION_DBG_LEVEL_ASSERTION,
[](const char *assert_message) { dbgAssert(false) << assert_message; }
[](const char *assert_message)
{
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "testing") << assert_message;
}
);
}

View File

@ -53,6 +53,7 @@ operator<<(ostream &os, const IPType &t)
return os << "Invalid(" << static_cast<uint>(t) << ")";
}
static const AlertInfo alert(AlertTeam::CORE, "IP address");
// Format an IP address. Use a pair, becuase it depends on the type (v4/v6)
ostream &
IPAddr::print(ostream &os) const
@ -63,12 +64,12 @@ IPAddr::print(ostream &os) const
switch (type) {
case IPType::V4: {
formatted_addr = inet_ntop(AF_INET, &v4, buf, sizeof(buf));
dbgAssert(formatted_addr == buf) << "Failed to convert an IPv4 address";
dbgAssert(formatted_addr == buf) << alert("conversion error") << "Failed to convert an IPv4 address";
break;
}
case IPType::V6: {
formatted_addr = inet_ntop(AF_INET6, &v6, buf, sizeof(buf));
dbgAssert(formatted_addr == buf) << "Failed to convert an IPv6 address";
dbgAssert(formatted_addr == buf) << alert("conversion error") << "Failed to convert an IPv6 address";
break;
}
case IPType::UNINITIALIZED: {
@ -115,8 +116,10 @@ ConnKey::reverse()
size_t
ConnKey::hash() const
{
dbgAssert(src.type != IPType::UNINITIALIZED) << "ConnKey::hash was called on an uninitialized object";
size_t seed = 0; // XXX: random seed for security?
dbgAssert(src.type != IPType::UNINITIALIZED)
<< alert("hashing")
<< "ConnKey::hash was called on an uninitialized object";
size_t seed = 0;
hashCombine(seed, static_cast<u_char>(src.type));
hashCombine(seed, src.proto);
hashCombine(seed, src);

View File

@ -80,7 +80,11 @@ cptestParseHex(const string &hex_text)
size_t l = t.size();
if (l==0) continue;
if (t[l-1]==':') continue; // tcpdump uses xxxx: to mark offsets, not data. So ignore it.
dbgAssert(t.size() %2 == 0) << "Expecting an even number of hex digits, " << t << " is invalid";
dbgAssert(t.size() %2 == 0)
<< AlertInfo(AlertTeam::CORE, "testing")
<< "Expecting an even number of hex digits, "
<< t
<< " is invalid";
for (uint i=0; i<t.size()/2; i++) {
u_char n = strtoul(t.substr(i*2, 2).c_str(), nullptr, 16);
v.push_back(n);

View File

@ -415,7 +415,7 @@ TCPPacket::Impl::emit_tcp_options(vector<u_char> &pkt) const
while (optbuf.size()%4 != 0) {
vec_append(optbuf, TCPOption::NOP);
}
dbgAssert(optbuf.size() <= 40) << "too many tcp options. max is 40 bytes";
dbgAssert(optbuf.size() <= 40) << AlertInfo(AlertTeam::CORE, "testing") << "too many tcp options. max is 40 bytes";
vec_append(pkt, optbuf);
}

View File

@ -8,7 +8,7 @@ TEST(CPTest, PrepareToDie)
{
cptestPrepareToDie();
auto die = []() {
dbgAssert(false) << "You killed my father";
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "testing") << "You killed my father";
};
EXPECT_DEATH(die(), "You killed my father");
}

View File

@ -26,6 +26,7 @@
#include "config.h"
#include "i_instance_awareness.h"
#include "i_signal_handler.h"
#include "hash_combine.h"
using namespace std;
@ -283,6 +284,16 @@ private:
S2C_PARAM(string, output);
};
void
AlertInfo::evalParams()
{
id = 0;
hashCombine(id, family_id);
hashCombine(id, functionality);
hashCombine(id, description);
hashCombine(id, static_cast<size_t>(team));
}
// LCOV_EXCL_START - function is covered in unit-test, but not detected bt gcov
Debug::Debug(
const string &file_name,
@ -830,6 +841,14 @@ Debug::isCommunicationFlag(const DebugFlags &flag)
);
}
void
Debug::sendAlert(const AlertInfo &alert)
{
for (auto &added_stream : current_active_streams) {
added_stream->sendAlert(alert);
}
}
Debug::DebugLevel Debug::lowest_global_level = default_level;
I_TimeGet *Debug::time = nullptr;
I_MainLoop *Debug::mainloop = nullptr;

View File

@ -55,6 +55,7 @@ public:
);
virtual void finishMessage() { *stream << std::endl; }
virtual void sendAlert(const AlertInfo &) {}
std::ostream * getStream() const { return stream; }
@ -112,6 +113,7 @@ public:
) override;
void finishMessage() override;
void sendAlert(const AlertInfo &_alert) override { possible_alert = _alert; }
private:
void sendBufferedMessages();
@ -133,6 +135,7 @@ private:
std::string trace_id;
std::string span_id;
uint line;
Maybe<AlertInfo, void> possible_alert = genError("");
};
#endif // __DEBUG_EX_H__

View File

@ -39,11 +39,32 @@ void doPMExecTrace() { dbgTrace(D_PM_EXEC) << "PM_EXEC trace message"; line = to
template <typename ...Args> void doManyFlags(Args ...args) { dbgDebug(args...) << "stab"; line = to_string(__LINE__); }
TEST(DebugBaseTest, alert_obkect)
{
AlertInfo alert1(AlertTeam::CORE, "testing");
EXPECT_EQ(alert1.getTeam(), AlertTeam::CORE);
EXPECT_EQ(alert1.getFunctionality(), "testing");
EXPECT_EQ(alert1.getDescription(), "");
EXPECT_EQ(alert1.getFamilyId(), 0u);
EXPECT_NE(alert1.getId(), 0u);
auto alert2 = alert1("additional data", 5);
EXPECT_EQ(alert2.getTeam(), AlertTeam::CORE);
EXPECT_EQ(alert2.getFunctionality(), "testing");
EXPECT_EQ(alert2.getDescription(), "additional data");
EXPECT_EQ(alert2.getFamilyId(), 5u);
EXPECT_NE(alert2.getId(), 0u);
EXPECT_NE(alert1.getId(), alert2.getId());
}
TEST(DebugBaseTest, death_on_panic)
{
cptestPrepareToDie();
EXPECT_DEATH(dbgAssert(1==2) << "Does your school teach otherwise?", "Does your school teach otherwise?");
EXPECT_DEATH(
dbgAssert(1==2) << AlertInfo(AlertTeam::CORE, "testing") << "Does your school teach otherwise?",
"Does your school teach otherwise?"
);
}
TEST(DebugBaseTest, default_levels)
@ -1014,7 +1035,7 @@ TEST(DebugFogTest, fog_stream)
" \"agentId\": \"Unknown\",\n"
" \"issuingFunction\": \"handleThresholdReach\",\n"
" \"issuingFile\": \"debug_streams.cc\",\n"
" \"issuingLine\": 344,\n"
" \"issuingLine\": 364,\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
@ -1117,3 +1138,123 @@ TEST(DebugFogTest, fog_stream)
EXPECT_CALL(mock_mainloop, stop(0));
Debug::fini();
}
TEST(DebugFogTest, alert_fog_stream)
{
ConfigComponent conf;
::Environment env;
env.preload();
env.init();
stringstream capture_debug;
conf.preload();
StrictMock<MockMainLoop> mock_mainloop;
StrictMock<MockTimeGet> mock_time;
NiceMock<MockAgentDetails> mock_agent_details;
ON_CALL(mock_agent_details, getFogDomain()).WillByDefault(Return(Maybe<string>(string("fog_domain.com"))));
ON_CALL(mock_agent_details, getFogPort()).WillByDefault(Return(Maybe<uint16_t>(443)));
EXPECT_CALL(mock_agent_details, getAgentId()).WillRepeatedly(Return("Unknown"));
EXPECT_CALL(mock_agent_details, getOrchestrationMode()).WillRepeatedly(Return(OrchestrationMode::ONLINE));
EXPECT_CALL(mock_time, getWalltimeStr(_)).WillRepeatedly(Return(string("2016-11-13T17:31:24.087")));
I_MainLoop::Routine send_debug_routine = nullptr;
EXPECT_CALL(mock_mainloop, addRecurringRoutine(_, _, _, _, _))
.WillOnce(DoAll(SaveArg<2>(&send_debug_routine), Return(0)));
StrictMock<MockMessaging> messaging_mock;
string message_body;
EXPECT_CALL(messaging_mock, sendAsyncMessage(
_,
"/api/v1/agents/events/bulk",
_,
_,
_,
_
)).WillRepeatedly(SaveArg<2>(&message_body));
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(
vector<string>{"--orchestration-mode=online_mode"}
);
Debug::preload();
string config_json =
"{"
" \"Debug I/S\": {"
" \"Sent debug bulk size\": ["
" {"
" \"value\": 2"
" }"
" ]"
" },"
" \"Debug\": [{"
" \"Streams\": ["
" {"
" \"Output\": \"FOG\""
" },"
" {"
" \"Output\": \"STDOUT\""
" }"
" ]"
" }]"
"}";
istringstream ss(config_json);
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(ss);
Debug::DebugAlert("MockFile", "MockFunction", 0, Debug::DebugLevel::ERROR, D_FW).getStreamAggr()
<< AlertInfo(AlertTeam::CORE, "testing")
<< "Generic error message";
string expected_message =
"{\n"
" \"logs\": [\n"
" {\n"
" \"id\": 1,\n"
" \"log\": {\n"
" \"eventTime\": \"2016-11-13T17:31:24.087\",\n"
" \"eventName\": \"Debug message\",\n"
" \"eventSeverity\": \"High\",\n"
" \"eventPriority\": \"Low\",\n"
" \"eventType\": \"Code Related\",\n"
" \"eventLevel\": \"Log\",\n"
" \"eventLogLevel\": \"error\",\n"
" \"eventAudience\": \"Internal\",\n"
" \"eventAudienceTeam\": \"\",\n"
" \"eventFrequency\": 0,\n"
" \"eventTags\": [\n"
" \"Informational\"\n"
" ],\n"
" \"eventSource\": {\n"
" \"agentId\": \"Unknown\",\n"
" \"issuingFunction\": \"MockFunction\",\n"
" \"issuingFile\": \"MockFile\",\n"
" \"issuingLine\": 0,\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
" \"serviceName\": \"Unnamed Nano Service\"\n"
" },\n"
" \"eventData\": {\n"
" \"eventMessage\": \"Generic error message\",\n"
" \"eventId\": 6255310698607853351,\n"
" \"eventFamilyId\": 0,\n"
" \"eventFunctionality\": \"testing\",\n"
" \"eventDescription\": \"\",\n"
" \"eventResponseTeam\": \"Core\"\n"
" }\n"
" }\n"
" }\n"
" ]\n"
"}";
send_debug_routine();
EXPECT_EQ(message_body, expected_message);
EXPECT_CALL(mock_mainloop, doesRoutineExist(0)).WillOnce(Return(true));
EXPECT_CALL(mock_mainloop, stop(0));
Debug::fini();
}

View File

@ -230,6 +230,18 @@ DebugFogStream::printHeader(
}
}
static string
getTeam(const Maybe<AlertInfo, void> &alert)
{
switch((*alert).getTeam()) {
case AlertTeam::CORE: return "Core";
case AlertTeam::WAAP: return "Waap";
case AlertTeam::SDWAN: return "SDWAN";
case AlertTeam::IOT: return "IoT";
}
return "Core";
}
void
DebugFogStream::finishMessage()
{
@ -265,6 +277,14 @@ DebugFogStream::finishMessage()
);
message_to_fog << LogField("eventMessage", message.str());
if (possible_alert.ok()) {
message_to_fog << LogField("eventId", (*possible_alert).getId());
message_to_fog << LogField("eventFamilyId", (*possible_alert).getFamilyId());
message_to_fog << LogField("eventFunctionality", (*possible_alert).getFunctionality());
message_to_fog << LogField("eventDescription", (*possible_alert).getDescription());
message_to_fog << LogField("eventResponseTeam", getTeam(possible_alert));
}
if (!getConfigurationWithDefault<bool>(true, "Debug I/S", "Enable bulk of debugs")) {
LogRest rest(move(message_to_fog));
Singleton::Consume<I_MainLoop>::by<Debug>()->addOneTimeRoutine(
@ -370,18 +390,20 @@ DebugFogStream::getSeverity() const
return Severity::CRITICAL;
}
static const AlertInfo alert(AlertTeam::CORE, "debug configuration");
LogLevel
DebugFogStream::getLogLevel() const
{
switch (level) {
case Debug::DebugLevel::NOISE: dbgAssert(false) << "Impossible LogLevel 'Noise'"; break;
case Debug::DebugLevel::NOISE: dbgAssert(false) << alert << "Impossible LogLevel 'Noise'"; break;
case Debug::DebugLevel::TRACE: return LogLevel::TRACE;
case Debug::DebugLevel::DEBUG: return LogLevel::DEBUG;
case Debug::DebugLevel::WARNING: return LogLevel::WARNING;
case Debug::DebugLevel::INFO: return LogLevel::INFO;
case Debug::DebugLevel::ERROR: return LogLevel::ERROR;
case Debug::DebugLevel::ASSERTION: return LogLevel::ERROR;
case Debug::DebugLevel::NONE: dbgAssert(false) << "Impossible LogLevel 'None'"; break;
case Debug::DebugLevel::NONE: dbgAssert(false) << alert << "Impossible LogLevel 'None'"; break;
}
return LogLevel::INFO;

View File

@ -42,6 +42,8 @@ Context::getAllStrings(const EnvKeyAttr::ParamAttr &param) const
return result;
}
static const AlertInfo alert(AlertTeam::CORE, "environment contexts");
const std::string
Context::convertToString(MetaDataType type)
{
@ -58,9 +60,9 @@ Context::convertToString(MetaDataType type)
case MetaDataType::Direction: return "direction";
case MetaDataType::Email: return "email";
case MetaDataType::COUNT:
dbgAssert(false) << "COUNT is not a valid meta data type";
dbgAssert(false) << alert << "COUNT is not a valid meta data type";
}
dbgAssert(false) << "Reached impossible case with type=" << static_cast<int>(type);
dbgAssert(false) << alert << "Reached impossible case with type=" << static_cast<int>(type);
return "";
}

View File

@ -213,8 +213,9 @@ Environment::Impl::registerContext(Context *ptr)
void
Environment::Impl::unregisterContext(Context *ptr)
{
dbgAssert(active_contexts.first.back() == ptr) <<
"Contexts are supposed to unregister in reverse order to their registration";
dbgAssert(active_contexts.first.back() == ptr)
<< AlertInfo(AlertTeam::CORE, "environment contexts")
<< "Contexts are supposed to unregister in reverse order to their registration";
active_contexts.first.pop_back();
}

View File

@ -97,7 +97,7 @@ Span::convertSpanContextTypeToString(ContextType type)
return "Follows from";
}
}
dbgAssert(false) << "Span context not supported";
dbgAssert(false) << AlertInfo(AlertTeam::CORE, "tracing") << "Span context not supported";
return string();
}

View File

@ -32,7 +32,14 @@ public:
}
operator const T *() const { return ptr; }
const T & operator*() const { dbgAssert(ptr != nullptr) << "Accessing a moved pointer"; return *ptr; }
const T &
operator*() const
{
dbgAssert(ptr != nullptr) << AlertInfo(AlertTeam::CORE, "buffer i/s") << "Accessing a moved pointer";
return *ptr;
}
const T * operator->() const { return ptr; }
private:

View File

@ -36,6 +36,58 @@ class I_SignalHandler;
namespace Config { enum class Errors; }
std::ostream & operator<<(std::ostream &, const Config::Errors &);
enum class AlertTeam { CORE, WAAP, SDWAN, IOT };
class AlertInfo
{
public:
template <typename ... Args>
AlertInfo(AlertTeam _team, const std::string &func, const Args & ... args) : team(_team), functionality(func)
{
evalParams(args ...);
}
template <typename ... Args>
AlertInfo
operator()(const Args & ... args) const
{
AlertInfo res = *this;
res.evalParams(args ...);
return res;
}
AlertTeam getTeam() const { return team; }
const std::string & getFunctionality() const { return functionality; }
const std::string & getDescription() const { return description; }
std::size_t getId() const { return id; }
std::size_t getFamilyId() const { return family_id; }
private:
template <typename ... Args>
void
evalParams(const std::string &_description, const Args & ... args)
{
description = _description;
evalParams(args ...);
}
template <typename ... Args>
void
evalParams(const std::size_t &fam_id, const Args & ... args)
{
family_id = fam_id;
evalParams(args ...);
}
void evalParams();
AlertTeam team;
std::string functionality;
std::size_t id;
std::size_t family_id = 0;
std::string description;
};
class Debug
:
Singleton::Consume<I_TimeGet>,
@ -93,6 +145,8 @@ public:
std::set<std::ostream *> streams;
};
class DebugAlert;
class DebugLockState
{
private:
@ -208,6 +262,7 @@ private:
);
void isCommunicationFlag(const DebugFlags &flag);
void sendAlert(const AlertInfo &alert);
static DebugLevel lowest_global_level;
static I_TimeGet *time;
@ -225,6 +280,34 @@ private:
std::set<std::shared_ptr<DebugStream>> current_active_streams;
};
class Debug::DebugAlert
{
class DebugAlertImpl
{
public:
DebugAlertImpl(Debug &_debug) : debug(_debug) {}
DebugStreamAggr &
operator<<(const AlertInfo &alert) __attribute__((warn_unused_result))
{
debug.sendAlert(alert);
return debug.getStreamAggr();
}
private:
Debug &debug;
};
public:
template <typename ... Args> DebugAlert(const Args & ... args) : debug(args...) {}
DebugAlertImpl getStreamAggr() __attribute__((warn_unused_result)) { return DebugAlertImpl(debug); }
private:
Debug debug;
};
#define USE_DEBUG_FLAG(x) extern const Debug::DebugFlags x
// This function extract the base name from a full path.
@ -245,7 +328,7 @@ getBaseName(const char *iter, const char *base)
#define dbgAssert(cond) \
if (CP_LIKELY(cond)) { \
} else Debug(__FILENAME__, __FUNCTION__, __LINE__).getStreamAggr()
} else Debug::DebugAlert(__FILENAME__, __FUNCTION__, __LINE__).getStreamAggr()
// Macros to allow simple debug messaging
#define DBG_GENERIC(level, ...) \

View File

@ -320,7 +320,7 @@ template <typename T, typename TErr>
const T &
Maybe<T, TErr>::unpack() const
{
dbgAssert(set) << "Maybe value is not set";
dbgAssert(set) << AlertInfo(AlertTeam::CORE, "maybe i/s") << "Maybe value is not set";
return val;
}
@ -328,7 +328,7 @@ template <typename T, typename TErr>
T &&
Maybe<T, TErr>::unpackMove()
{
dbgAssert(set) << "No value to be moved";
dbgAssert(set) << AlertInfo(AlertTeam::CORE, "maybe i/s") << "No value to be moved";
return std::move(val);
}
@ -336,7 +336,7 @@ template <typename T, typename TErr>
TErr
Maybe<T, TErr>::getErr() const
{
dbgAssert(!set) << "Maybe value is set";
dbgAssert(!set) << AlertInfo(AlertTeam::CORE, "maybe i/s") << "Maybe value is set";
return err.err;
}
@ -344,7 +344,7 @@ template <typename T, typename TErr>
const Error<TErr> &
Maybe<T, TErr>::passErr() const
{
dbgAssert(!set) << "Maybe value is set";
dbgAssert(!set) << AlertInfo(AlertTeam::CORE, "maybe i/s") << "Maybe value is set";
return err;
}

View File

@ -110,7 +110,9 @@ template <typename Key>
const Key &
Table<Key>::Impl::ExpList::getEarliest() const
{
dbgAssert(!list.empty()) << "Cannot access the earliest member of an empty list";
dbgAssert(!list.empty())
<< AlertInfo(AlertTeam::CORE, "table")
<< "Cannot access the earliest member of an empty list";
return list.back().getKey();
}

View File

@ -36,6 +36,7 @@ class I_Intelligence_IS_V2
{
public:
virtual bool sendInvalidation(const Intelligence::Invalidation &invalidation) const = 0;
virtual bool isIntelligenceHealthy() const = 0;
virtual Maybe<uint> registerInvalidation(
const Intelligence::Invalidation &invalidation,
const std::function<void(const Intelligence::Invalidation &)> &callback

View File

@ -48,6 +48,8 @@ public:
return addRestCall(oper, uri, std::make_unique<SpecificRestInit<T>>());
}
virtual bool addGetCall(const std::string &uri, const std::function<std::string()> &callback) = 0;
virtual uint16_t getListeningPort() const = 0;
protected:

View File

@ -24,6 +24,7 @@ public:
using Response = Intelligence::Response;
MOCK_CONST_METHOD1(sendInvalidation, bool(const Invalidation &invalidation));
MOCK_CONST_METHOD0(isIntelligenceHealthy, bool(void));
MOCK_METHOD2(registerInvalidation, Maybe<uint>(const Invalidation &invalidation, const InvalidationCb &callback));
MOCK_METHOD1(unregisterInvalidation, void(uint id));
MOCK_CONST_METHOD5(

View File

@ -9,6 +9,7 @@ class MockRestApi : public Singleton::Provide<I_RestApi>::From<MockProvider<I_Re
{
public:
MOCK_CONST_METHOD0(getListeningPort, uint16_t());
MOCK_METHOD2(addGetCall, bool(const std::string &, const std::function<std::string()> &));
// You can't mock a function with an R-value reference. So mock a slightly different one
MOCK_METHOD3(mockRestCall, bool(RestAction, const std::string &, const std::unique_ptr<RestInit> &));

View File

@ -34,7 +34,7 @@ DEFINE_FLAG(D_INFRA, D_ALL)
DEFINE_FLAG(D_SIGNAL_HANDLER, D_INFRA)
DEFINE_FLAG(D_TENANT_MANAGER, D_INFRA)
DEFINE_FLAG(D_MONITORING, D_INFRA)
DEFINE_FLAG(D_HEALTH_CHECK_MANAGER, D_INFRA)
DEFINE_FLAG(D_SERVICE_HEALTH_STATUS, D_INFRA)
DEFINE_FLAG(D_REPORT, D_INFRA)
DEFINE_FLAG(D_REPORT_BULK, D_REPORT)
DEFINE_FLAG(D_TRACE, D_INFRA)
@ -137,6 +137,7 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
DEFINE_FLAG(D_HTTP_MANAGER, D_COMPONENT)
DEFINE_FLAG(D_ORCHESTRATOR, D_COMPONENT)
DEFINE_FLAG(D_HEALTH_CHECK_MANAGER, D_ORCHESTRATOR)
DEFINE_FLAG(D_HEALTH_CHECK, D_ORCHESTRATOR)
DEFINE_FLAG(D_AGENT_DETAILS, D_ORCHESTRATOR)
DEFINE_FLAG(D_LOCAL_POLICY, D_ORCHESTRATOR)
@ -166,7 +167,6 @@ DEFINE_FLAG(D_COMPONENT, D_ALL)
DEFINE_FLAG(D_IOT_QUERY_INTELLIGENCE, D_IOT_AUXILIARY)
DEFINE_FLAG(D_IOT_SAVE_PERSISTENT, D_IOT_AUXILIARY)
DEFINE_FLAG(D_IOT_DOCKER, D_IOT_AUXILIARY)
DEFINE_FLAG(D_IOT_REST_AUTHENTICATION, D_IOT_AUXILIARY)
DEFINE_FLAG(D_IOT_ENFORCE, D_IOT_NEXT)
DEFINE_FLAG(D_IOT_ENFORCE_POLICY, D_IOT_ENFORCE)
DEFINE_FLAG(D_IOT_ENFORCE_ASSETS, D_IOT_ENFORCE)

View File

@ -16,7 +16,9 @@
#include <chrono>
#include <vector>
#include <map>
#include "metric/metric_metadata.h"
#include "metric/metric_calc.h"
#include "metric/all_metric_event.h"
#include "i_mainloop.h"
@ -26,6 +28,7 @@
#include "i_messaging.h"
#include "i_rest_api.h"
#include "report/report_enums.h"
#include "flags.h"
namespace MetricCalculations
{
@ -38,6 +41,10 @@ namespace MetricCalculations
template <typename PrintableKey, typename Metric> class MetricMap;
} // MetricCalculations
MetricMetadata::DotName operator"" _dot(const char *, std::size_t);
MetricMetadata::Units operator"" _unit(const char *, std::size_t);
MetricMetadata::Description operator"" _desc(const char *, std::size_t);
class LogRest;
class GenericMetric
@ -51,6 +58,8 @@ class GenericMetric
public Listener<AllMetricEvent>
{
public:
enum class Stream { FOG, DEBUG, PROMETHEUS, AIOPS, COUNT };
void
init(
const std::string &_metric_name,
@ -79,7 +88,8 @@ public:
static std::string getName() { return "GenericMetric"; }
std::string generateReport(bool with_reset);
std::string generateReport() const;
void resetMetrics();
void upon(const AllMetricEvent &) override;
std::string respond(const AllMetricEvent &event) override;
std::string getListenerName() const override;
@ -87,6 +97,9 @@ public:
std::string getMetricName() const;
std::chrono::seconds getReportInterval() const;
void turnOnStream(Stream stream) { active_streams.setFlag(stream); }
void turnOffStream(Stream stream) { active_streams.unsetFlag(stream); }
protected:
virtual void sendLog(const LogRest &metric_client_rest) const;
@ -98,6 +111,7 @@ private:
void handleMetricStreamSending();
void generateLog();
void generateDebug();
I_MainLoop *i_mainloop;
I_TimeGet *i_time;
@ -107,12 +121,14 @@ private:
ReportIS::Audience audience;
std::chrono::seconds report_interval;
std::vector<MetricCalc *> calcs;
Flags<Stream> active_streams;
bool reset;
bool force_buffering = false;
Context ctx;
};
#include "metric/counter.h"
#include "metric/no_reset_counter.h"
#include "metric/max.h"
#include "metric/min.h"
#include "metric/average.h"

Some files were not shown because too many files have changed in this diff Show More