mirror of
https://github.com/openappsec/openappsec.git
synced 2025-11-16 01:12:18 +03:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01770475ec | ||
|
|
78b114a274 | ||
|
|
81b1aec487 | ||
|
|
be6591a670 | ||
|
|
663782009c | ||
|
|
9392bbb26c | ||
|
|
46682bcdce | ||
|
|
057bc42375 | ||
|
|
88e0ccd308 | ||
|
|
4241b9c574 | ||
|
|
4af9f18ada | ||
|
|
3b533608b1 | ||
|
|
74bb3086ec | ||
|
|
504d1415a5 | ||
|
|
18b1b63c42 | ||
|
|
ded2a5ffc2 | ||
|
|
1254bb37b2 | ||
|
|
cf16343caa | ||
|
|
78c4209406 | ||
|
|
3c8672c565 | ||
|
|
48d6baed3b | ||
|
|
8770257a60 | ||
|
|
fd5d093b24 | ||
|
|
d6debf8d8d | ||
|
|
395b754575 | ||
|
|
dc000372c4 | ||
|
|
941c641174 | ||
|
|
fdc148aa9b | ||
|
|
307fd8897d | ||
|
|
afd2b4930b | ||
|
|
1fb9a29223 | ||
|
|
253ca70de6 | ||
|
|
938f625535 | ||
|
|
183d14fc55 | ||
|
|
1f3d4ed5e1 | ||
|
|
fdbd6d3786 | ||
|
|
4504138a4a | ||
|
|
66ed4a8d81 | ||
|
|
189c9209c9 | ||
|
|
1a1580081c | ||
|
|
942b2ef8b4 | ||
|
|
7a7f65a77a | ||
|
|
ecbb34bc17 |
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required (VERSION 2.8.4)
|
||||
project (ngen)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wno-terminate")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -fPIC -Wall -Wno-terminate")
|
||||
|
||||
execute_process(COMMAND grep -c "Alpine Linux" /etc/os-release OUTPUT_VARIABLE IS_ALPINE)
|
||||
if(NOT IS_ALPINE EQUAL "0")
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
# 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.
|
||||
# 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.
|
||||
|
||||
version: "3"
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ var_fog_address=
|
||||
var_proxy=
|
||||
var_mode=
|
||||
var_token=
|
||||
var_ignore=
|
||||
init=
|
||||
|
||||
if [ ! -f /nano-service-installers/$ORCHESTRATION_INSTALLATION_SCRIPT ]; then
|
||||
@@ -33,6 +34,8 @@ while true; do
|
||||
var_proxy="$1"
|
||||
elif [ "$1" == "--hybrid-mode" ] || [ "$1" == "--standalone" ]; then
|
||||
var_mode="--hybrid_mode"
|
||||
elif [ "$1" == "--no-upgrade" ]; then
|
||||
var_ignore="--ignore all"
|
||||
elif [ "$1" == "--token" ]; then
|
||||
shift
|
||||
var_token="$1"
|
||||
@@ -47,6 +50,7 @@ fi
|
||||
|
||||
orchestration_service_installation_flags="--container_mode --skip_registration"
|
||||
if [ ! -z $var_token ]; then
|
||||
export AGENT_TOKEN="$var_token"
|
||||
orchestration_service_installation_flags="$orchestration_service_installation_flags --token $var_token"
|
||||
fi
|
||||
if [ ! -z $var_fog_address ]; then
|
||||
@@ -59,6 +63,9 @@ fi
|
||||
if [ ! -z $var_mode ]; then
|
||||
orchestration_service_installation_flags="$orchestration_service_installation_flags $var_mode"
|
||||
fi
|
||||
if [ ! -z "$var_ignore" ]; then
|
||||
orchestration_service_installation_flags="$orchestration_service_installation_flags $var_ignore"
|
||||
fi
|
||||
|
||||
|
||||
/nano-service-installers/$ORCHESTRATION_INSTALLATION_SCRIPT --install $orchestration_service_installation_flags
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,6 @@ add_subdirectory(signal_handler)
|
||||
add_subdirectory(gradual_deployment)
|
||||
add_subdirectory(packet)
|
||||
add_subdirectory(pending_key)
|
||||
add_subdirectory(health_check_manager)
|
||||
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(attachment-intakers)
|
||||
|
||||
@@ -1698,7 +1698,7 @@ private:
|
||||
}
|
||||
};
|
||||
mainloop->addFileRoutine(
|
||||
I_MainLoop::RoutineType::RealTime,
|
||||
I_MainLoop::RoutineType::System,
|
||||
server_sock,
|
||||
accept_attachment_routine,
|
||||
"Nginx Attachment registration listener",
|
||||
|
||||
@@ -306,17 +306,20 @@ UsersAllIdentifiersConfig::parseXForwardedFor(const string &str) const
|
||||
void
|
||||
UsersAllIdentifiersConfig::setXFFValuesToOpaqueCtx(const HttpHeader &header, ExtractType type) const
|
||||
{
|
||||
auto i_transaction_table = Singleton::Consume<I_TableSpecific<SessionID>>::by<NginxAttachment>();
|
||||
if (!i_transaction_table || !i_transaction_table->hasState<NginxAttachmentOpaque>()) {
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Can't get the transaction table";
|
||||
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";
|
||||
return;
|
||||
};
|
||||
auto i_transaction_table = Singleton::Consume<I_TableSpecific<SessionID>>::by<NginxAttachment>();
|
||||
if (!i_transaction_table || !i_transaction_table->hasState<NginxAttachmentOpaque>()) {
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Can't get the transaction table";
|
||||
return;
|
||||
}
|
||||
NginxAttachmentOpaque &opaque = i_transaction_table->getState<NginxAttachmentOpaque>();
|
||||
|
||||
if (type == ExtractType::SOURCEIDENTIFIER) {
|
||||
opaque.setSourceIdentifier(header.getKey(), value.unpack());
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER)
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
// 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 "generic_rulebase/assets_config.h"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "generic_rulebase/generic_rulebase_utils.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "ip_utilities.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
void
|
||||
RuleAsset::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
archive_in(cereal::make_nvp("assetId", asset_id));
|
||||
archive_in(cereal::make_nvp("assetName", asset_name));
|
||||
archive_in(cereal::make_nvp("assetUrls", asset_urls));
|
||||
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Adding asset with UID: " << asset_id;
|
||||
}
|
||||
|
||||
void
|
||||
RuleAsset::AssetUrl::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
archive_in(cereal::make_nvp("protocol", protocol));
|
||||
transform(protocol.begin(), protocol.end(), protocol.begin(), [](unsigned char c) { return tolower(c); });
|
||||
|
||||
archive_in(cereal::make_nvp("ip", ip));
|
||||
archive_in(cereal::make_nvp("port", port));
|
||||
|
||||
int value;
|
||||
if (protocol == "*") {
|
||||
is_any_proto = true;
|
||||
} else {
|
||||
is_any_proto = false;
|
||||
try {
|
||||
value = 0;
|
||||
if(protocol == "udp") value = IPPROTO_UDP;
|
||||
if(protocol == "tcp") value = IPPROTO_TCP;
|
||||
if(protocol == "dccp") value = IPPROTO_DCCP;
|
||||
if(protocol == "sctp") value = IPPROTO_SCTP;
|
||||
if(protocol == "icmp") value = IPPROTO_ICMP;
|
||||
if(protocol == "icmpv6") value = IPPROTO_ICMP;
|
||||
|
||||
if (value > static_cast<int>(UINT8_MAX) || value < 0) {
|
||||
dbgWarning(D_RULEBASE_CONFIG)
|
||||
<< "provided value is not a legal IP protocol number. Value: "
|
||||
<< protocol;
|
||||
} else {
|
||||
parsed_proto = value;
|
||||
}
|
||||
} catch (...) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "provided value is not a legal IP protocol. Value: " << protocol;
|
||||
}
|
||||
}
|
||||
|
||||
if (port == "*") {
|
||||
is_any_port = true;
|
||||
} else {
|
||||
is_any_port = false;
|
||||
try {
|
||||
value = stoi(port);
|
||||
if (value > static_cast<int>(UINT16_MAX) || value < 0) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "provided value is not a legal port number. Value: " << port;
|
||||
} else {
|
||||
parsed_port = value;
|
||||
}
|
||||
} catch (...) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "provided value is not a legal port. Value: " << port;
|
||||
}
|
||||
}
|
||||
|
||||
if (ip == "*") {
|
||||
is_any_ip = true;
|
||||
} else {
|
||||
is_any_ip = false;
|
||||
auto ip_addr = IPAddr::createIPAddr(ip);
|
||||
if (!ip_addr.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Could not create IP address. Error: " << ip_addr.getErr();
|
||||
} else {
|
||||
parsed_ip = ConvertToIpAddress(ip_addr.unpackMove());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpAddress
|
||||
RuleAsset::AssetUrl::ConvertToIpAddress(const IPAddr &addr)
|
||||
{
|
||||
IpAddress address;
|
||||
switch (addr.getType()) {
|
||||
case IPType::UNINITIALIZED: {
|
||||
address.addr4_t = {0};
|
||||
address.ip_type = IP_VERSION_ANY;
|
||||
break;
|
||||
}
|
||||
case IPType::V4: {
|
||||
address.addr4_t = addr.getIPv4();
|
||||
address.ip_type = IP_VERSION_4;
|
||||
break;
|
||||
}
|
||||
case IPType::V6: {
|
||||
address.addr6_t = addr.getIPv6();
|
||||
address.ip_type = IP_VERSION_6;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
address.addr4_t = {0};
|
||||
address.ip_type = IP_VERSION_ANY;
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Unsupported IP type: " << static_cast<int>(addr.getType());
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
const Assets Assets::empty_assets_config = Assets();
|
||||
|
||||
void
|
||||
Assets::preload()
|
||||
{
|
||||
registerExpectedSetting<Assets>("rulebase", "usedAssets");
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
// 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 "generic_rulebase/evaluators/asset_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/assets_config.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
string AssetMatcher::ctx_key = "asset_id";
|
||||
|
||||
AssetMatcher::AssetMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(AssetMatcher::getName(), params.size(), 1, 1);
|
||||
asset_id = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
AssetMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<AssetMatcher>();
|
||||
auto bc_asset_id_ctx = env->get<GenericConfigId>(AssetMatcher::ctx_key);
|
||||
|
||||
if (bc_asset_id_ctx.ok()) {
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Asset ID: "
|
||||
<< asset_id
|
||||
<< "; Current set assetId context: "
|
||||
<< *bc_asset_id_ctx;
|
||||
} else {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Asset ID: " << asset_id << ". Empty context";
|
||||
}
|
||||
|
||||
return bc_asset_id_ctx.ok() && *bc_asset_id_ctx == asset_id;
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
// 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 "generic_rulebase/evaluators/connection_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "ip_utilities.h"
|
||||
|
||||
using namespace std;
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
string IpAddressMatcher::ctx_key = "ipAddress";
|
||||
string SourceIpMatcher::ctx_key = "sourceIP";
|
||||
string DestinationIpMatcher::ctx_key = "destinationIP";
|
||||
string SourcePortMatcher::ctx_key = "sourcePort";
|
||||
string ListeningPortMatcher::ctx_key = "listeningPort";
|
||||
string IpProtocolMatcher::ctx_key = "ipProtocol";
|
||||
string UrlMatcher::ctx_key = "url";
|
||||
|
||||
Maybe<IPAddr>
|
||||
getIpAddrFromEnviroment(I_Environment *env, Context::MetaDataType enum_data_type, const string &str_data_type)
|
||||
{
|
||||
auto ip_str = env->get<string>(enum_data_type);
|
||||
if (!ip_str.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get " << str_data_type << " from the enviroment.";
|
||||
return genError("Failed to get " + str_data_type + " from the enviroment.");
|
||||
}
|
||||
return IPAddr::createIPAddr(ip_str.unpack());
|
||||
}
|
||||
|
||||
bool
|
||||
checkIfIpInRangesVec(const vector<CustomRange<IPAddr>> &values, const IPAddr &ip_to_check)
|
||||
{
|
||||
if (values.size() == 0) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip addersses vector empty. Match is true.";
|
||||
return true;
|
||||
}
|
||||
for (const CustomRange<IPAddr> &range : values) {
|
||||
if (range.contains(ip_to_check)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip adderss matched: " << ip_to_check;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip adderss not match: " << ip_to_check;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
IpAddressMatcher::IpAddressMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<IPAddr>> ip_range = CustomRange<IPAddr>::createRange(param);
|
||||
if (!ip_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create ip. Error: " + ip_range.getErr();
|
||||
continue;
|
||||
}
|
||||
values.push_back(ip_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
IpAddressMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<IpAddressMatcher>();
|
||||
Maybe<IPAddr> subject_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::SubjectIpAddr,
|
||||
"subject ip address"
|
||||
);
|
||||
if (subject_ip.ok() && checkIfIpInRangesVec(values, subject_ip.unpack())) return true;
|
||||
|
||||
Maybe<IPAddr> other_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::OtherIpAddr,
|
||||
"other ip address"
|
||||
);
|
||||
if (other_ip.ok() && checkIfIpInRangesVec(values, other_ip.unpack())) return true;
|
||||
if (!subject_ip.ok() && !other_ip.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Error in getting subject ip and other ip from the enviroment";
|
||||
return false;
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip adderss didn't match";
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceIpMatcher::SourceIpMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<IPAddr>> ip_range = CustomRange<IPAddr>::createRange(param);
|
||||
if (!ip_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create source ip. Error: " + ip_range.getErr();
|
||||
continue;
|
||||
}
|
||||
values.push_back(ip_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
SourceIpMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<SourceIpMatcher>();
|
||||
auto direction_maybe = env->get<string>(Context::MetaDataType::Direction);
|
||||
if (!direction_maybe.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get direction from the enviroment.";
|
||||
return false;
|
||||
}
|
||||
string direction = direction_maybe.unpack();
|
||||
if (direction == "incoming") {
|
||||
Maybe<IPAddr> other_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::OtherIpAddr,
|
||||
"other ip address"
|
||||
);
|
||||
return other_ip.ok() && checkIfIpInRangesVec(values, other_ip.unpack());
|
||||
} else if (direction == "outgoing") {
|
||||
Maybe<IPAddr> subject_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::SubjectIpAddr,
|
||||
"subject ip address"
|
||||
);
|
||||
return subject_ip.ok() && checkIfIpInRangesVec(values, subject_ip.unpack());
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Source ip adderss didn't match";
|
||||
return false;
|
||||
}
|
||||
|
||||
DestinationIpMatcher::DestinationIpMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<IPAddr>> ip_range = CustomRange<IPAddr>::createRange(param);
|
||||
if (!ip_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create destination ip. Error: " + ip_range.getErr();
|
||||
continue;
|
||||
}
|
||||
values.push_back(ip_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
DestinationIpMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<DestinationIpMatcher>();
|
||||
auto direction_maybe = env->get<string>(Context::MetaDataType::Direction);
|
||||
if (!direction_maybe.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get direction.";
|
||||
return false;
|
||||
}
|
||||
string direction = direction_maybe.unpack();
|
||||
if (direction == "outgoing") {
|
||||
Maybe<IPAddr> other_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::OtherIpAddr,
|
||||
"other ip address"
|
||||
);
|
||||
return other_ip.ok() && checkIfIpInRangesVec(values, other_ip.unpack());
|
||||
} else if (direction == "incoming") {
|
||||
Maybe<IPAddr> subject_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::SubjectIpAddr,
|
||||
"subject ip address"
|
||||
);
|
||||
return subject_ip.ok() && checkIfIpInRangesVec(values, subject_ip.unpack());
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Destination ip adderss didn't match";
|
||||
return false;
|
||||
}
|
||||
|
||||
SourcePortMatcher::SourcePortMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<PortNumber>> port_range = CustomRange<PortNumber>::createRange(param);
|
||||
if (!port_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create source port.";
|
||||
continue;
|
||||
}
|
||||
values.push_back(port_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
SourcePortMatcher::evalVariable() const
|
||||
{
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Source is not a match";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ListeningPortMatcher::ListeningPortMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<PortNumber>> port_range = CustomRange<PortNumber>::createRange(param);
|
||||
if (!port_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create listening port range.";
|
||||
continue;
|
||||
}
|
||||
values.push_back(port_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
ListeningPortMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<ListeningPortMatcher>();
|
||||
auto port_str = env->get<string>(Context::MetaDataType::Port);
|
||||
if (!port_str.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get port from the enviroment.";
|
||||
return false;
|
||||
}
|
||||
PortNumber port;
|
||||
if (ConnKeyUtil::fromString(port_str.unpack(), port)) {
|
||||
if (values.size() == 0) return true;
|
||||
for (const CustomRange<PortNumber> &port_range : values) {
|
||||
if (port_range.contains(port)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Listening port is a match. Value: " << port_str.unpack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Listening port is not a match. Value: " << port_str.unpack();
|
||||
return false;
|
||||
}
|
||||
|
||||
IpProtocolMatcher::IpProtocolMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<IPProto>> proto_range = CustomRange<IPProto>::createRange(param);
|
||||
if (!proto_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create ip protocol.";
|
||||
continue;
|
||||
}
|
||||
values.push_back(proto_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
IpProtocolMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<IpProtocolMatcher>();
|
||||
auto proto_str = env->get<string>(Context::MetaDataType::Protocol);
|
||||
if (!proto_str.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get ip protocol from the enviroment.";
|
||||
return false;
|
||||
}
|
||||
IPProto protocol;
|
||||
if (ConnKeyUtil::fromString(proto_str.unpack(), protocol)) {
|
||||
if (values.size() == 0) return true;
|
||||
for (const CustomRange<IPProto> &proto_range : values) {
|
||||
if (proto_range.contains(protocol)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip protocol is a match. Value: " << proto_str.unpack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Source port is not a match. Value: " << proto_str.unpack();
|
||||
return false;
|
||||
}
|
||||
|
||||
UrlMatcher::UrlMatcher(const vector<string> ¶ms) : values(params) {}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
UrlMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<UrlMatcher>();
|
||||
auto curr_url_ctx = env->get<string>(Context::MetaDataType::Url);
|
||||
if (!curr_url_ctx.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get URL from the enviroment.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (values.size() == 0) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Matched URL on \"any\". Url: " << *curr_url_ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const string &url : values) {
|
||||
if (*curr_url_ctx == url) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Matched URL. Value: " << *curr_url_ctx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "URL is not a match. Value: " << *curr_url_ctx;
|
||||
return false;
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
// 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 "generic_rulebase/evaluators/http_transaction_data_eval.h"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#include "http_transaction_data.h"
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
#include "debug.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
using namespace EnvironmentHelper;
|
||||
|
||||
EqualHost::EqualHost(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("EqualHost", params.size(), 1, 1);
|
||||
host = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
EqualHost::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<EqualHost>();
|
||||
auto host_ctx = env->get<string>(HttpTransactionData::host_name_ctx);
|
||||
|
||||
if (!host_ctx.ok())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string lower_host_ctx = host_ctx.unpack();
|
||||
std::transform(lower_host_ctx.begin(), lower_host_ctx.end(), lower_host_ctx.begin(), ::tolower);
|
||||
|
||||
std::string lower_host = host;
|
||||
std::transform(lower_host.begin(), lower_host.end(), lower_host.begin(), ::tolower);
|
||||
|
||||
|
||||
if (lower_host_ctx == lower_host) return true;
|
||||
size_t pos = lower_host_ctx.find_last_of(':');
|
||||
if (pos == string::npos) return false;
|
||||
lower_host_ctx = string(lower_host_ctx.data(), pos);
|
||||
return lower_host_ctx == lower_host;
|
||||
}
|
||||
|
||||
WildcardHost::WildcardHost(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("WildcardHost", params.size(), 1, 1);
|
||||
host = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
WildcardHost::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<WildcardHost>();
|
||||
auto host_ctx = env->get<string>(HttpTransactionData::host_name_ctx);
|
||||
|
||||
if (!host_ctx.ok())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string lower_host_ctx = host_ctx.unpack();
|
||||
transform(lower_host_ctx.begin(), lower_host_ctx.end(), lower_host_ctx.begin(), ::tolower);
|
||||
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "found host in current context: " << lower_host_ctx;
|
||||
|
||||
size_t pos = lower_host_ctx.find_first_of(".");
|
||||
if (pos == string::npos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lower_host_ctx = "*" + lower_host_ctx.substr(pos, lower_host_ctx.length());
|
||||
|
||||
string lower_host = host;
|
||||
transform(lower_host.begin(), lower_host.end(), lower_host.begin(), ::tolower);
|
||||
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "trying to match host context with its corresponding wildcard address: "
|
||||
<< lower_host_ctx
|
||||
<< ". Matcher host: "
|
||||
<< lower_host;
|
||||
|
||||
if (lower_host_ctx == lower_host) return true;
|
||||
pos = lower_host_ctx.find_last_of(':');
|
||||
if (pos == string::npos) return false;
|
||||
lower_host_ctx = string(lower_host_ctx.data(), pos);
|
||||
return lower_host_ctx == lower_host;
|
||||
}
|
||||
|
||||
EqualListeningIP::EqualListeningIP(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("EqualListeningIP", params.size(), 1, 1);
|
||||
|
||||
auto maybe_ip = IPAddr::createIPAddr(params[0]);
|
||||
if (!maybe_ip.ok()) reportWrongParamType(getName(), params[0], "Not a valid IP Address");
|
||||
|
||||
listening_ip = maybe_ip.unpack();
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
EqualListeningIP::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<EqualListeningIP>();
|
||||
auto listening_ip_ctx = env->get<IPAddr>(HttpTransactionData::listening_ip_ctx);
|
||||
return listening_ip_ctx.ok() && listening_ip_ctx.unpack() == listening_ip;
|
||||
}
|
||||
|
||||
EqualListeningPort::EqualListeningPort(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("EqualListeningPort", params.size(), 1, 1);
|
||||
|
||||
try {
|
||||
listening_port = boost::lexical_cast<PortNumber>(params[0]);
|
||||
} catch (boost::bad_lexical_cast const&) {
|
||||
reportWrongParamType(getName(), params[0], "Not a valid port number");
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
EqualListeningPort::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<EqualListeningPort>();
|
||||
auto port_ctx = env->get<PortNumber>(HttpTransactionData::listening_port_ctx);
|
||||
|
||||
return port_ctx.ok() && port_ctx.unpack() == listening_port;
|
||||
}
|
||||
|
||||
BeginWithUri::BeginWithUri(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("BeginWithUri", params.size(), 1, 1);
|
||||
uri_prefix = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
BeginWithUri::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<BeginWithUri>();
|
||||
auto uri_ctx = env->get<string>(HttpTransactionData::uri_ctx);
|
||||
|
||||
if (!uri_ctx.ok())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string lower_uri_ctx = uri_ctx.unpack();
|
||||
std::transform(lower_uri_ctx.begin(), lower_uri_ctx.end(), lower_uri_ctx.begin(), ::tolower);
|
||||
|
||||
std::string lower_uri_prefix = uri_prefix;
|
||||
std::transform(lower_uri_prefix.begin(), lower_uri_prefix.end(), lower_uri_prefix.begin(), ::tolower);
|
||||
|
||||
return lower_uri_ctx.find(lower_uri_prefix) == 0;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// 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 "generic_rulebase/evaluators/practice_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
string PracticeMatcher::ctx_key = "practices";
|
||||
|
||||
PracticeMatcher::PracticeMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(PracticeMatcher::getName(), params.size(), 1, 1);
|
||||
practice_id = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
PracticeMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<PracticeMatcher>();
|
||||
auto bc_practice_id_ctx = env->get<set<GenericConfigId>>(PracticeMatcher::ctx_key);
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Trying to match practice. ID: "
|
||||
<< practice_id << ", Current set IDs: "
|
||||
<< makeSeparatedStr(bc_practice_id_ctx.ok() ? *bc_practice_id_ctx : set<GenericConfigId>(), ", ");
|
||||
if (bc_practice_id_ctx.ok()) {
|
||||
return bc_practice_id_ctx.unpack().count(practice_id) > 0;
|
||||
}
|
||||
|
||||
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
|
||||
return rule.ok() && rule.unpack().isPracticeActive(practice_id);
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
// 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 "generic_rulebase/evaluators/query_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "generic_rulebase/zones_config.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "enum_range.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
QueryMatcher::QueryMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() < 1) reportWrongNumberOfParams(QueryMatcher::getName(), params.size(), 1);
|
||||
|
||||
key = params.front();
|
||||
if (key == "any") {
|
||||
is_any = true;
|
||||
} else {
|
||||
values.reserve(params.size() - 1);
|
||||
for (uint i = 1; i < params.size() ; i++) {
|
||||
if (params[i] == "any") {
|
||||
values.clear();
|
||||
break;
|
||||
}
|
||||
values.insert(params[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const string
|
||||
QueryMatcher::contextKeyToString(Context::MetaDataType type)
|
||||
{
|
||||
if (type == Context::MetaDataType::SubjectIpAddr || type == Context::MetaDataType::OtherIpAddr) return "ip";
|
||||
return Context::convertToString(type);
|
||||
}
|
||||
|
||||
class QueryMatchSerializer
|
||||
{
|
||||
public:
|
||||
static const string req_attr_ctx_key;
|
||||
|
||||
template <typename Archive>
|
||||
void
|
||||
serialize(Archive &ar)
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<QueryMatcher>();
|
||||
auto req_attr = env->get<string>(req_attr_ctx_key);
|
||||
if (!req_attr.ok()) return;
|
||||
|
||||
try {
|
||||
ar(cereal::make_nvp(*req_attr, value));
|
||||
dbgDebug(D_RULEBASE_CONFIG)
|
||||
<< "Found value for requested attribute. Tag: "
|
||||
<< *req_attr
|
||||
<< ", Value: "
|
||||
<< value;
|
||||
} catch (exception &e) {
|
||||
dbgDebug(D_RULEBASE_CONFIG) << "Could not find values for requested attribute. Tag: " << *req_attr;
|
||||
ar.finishNode();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Values>
|
||||
bool
|
||||
matchValues(const Values &requested_vals) const
|
||||
{
|
||||
return value != "" && (requested_vals.empty() || requested_vals.count(value) > 0);
|
||||
}
|
||||
|
||||
private:
|
||||
string value;
|
||||
};
|
||||
|
||||
const string QueryMatchSerializer::req_attr_ctx_key = "requested attribute key";
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
QueryMatcher::evalVariable() const
|
||||
{
|
||||
if (is_any) return true;
|
||||
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<QueryMatcher>();
|
||||
auto local_asset_ctx = env->get<bool>("is local asset");
|
||||
bool is_remote_asset = local_asset_ctx.ok() && !(*local_asset_ctx);
|
||||
|
||||
QueryRequest request;
|
||||
for (Context::MetaDataType name : makeRange<Context::MetaDataType>()) {
|
||||
auto val = env->get<string>(name);
|
||||
if (val.ok()) {
|
||||
if ((name == Context::MetaDataType::SubjectIpAddr && is_remote_asset) ||
|
||||
(name == Context::MetaDataType::OtherIpAddr && !is_remote_asset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
request.addCondition(Condition::EQUALS, contextKeyToString(name), *val);
|
||||
}
|
||||
}
|
||||
if (request.empty()) return false;
|
||||
|
||||
request.setRequestedAttr(key);
|
||||
ScopedContext req_attr_key;
|
||||
req_attr_key.registerValue<string>(QueryMatchSerializer::req_attr_ctx_key, key);
|
||||
|
||||
I_Intelligence_IS_V2 *intelligence = Singleton::Consume<I_Intelligence_IS_V2>::by<Zone>();
|
||||
auto query_res = intelligence->queryIntelligence<QueryMatchSerializer>(request);
|
||||
if (!query_res.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to perform intelligence query. Error: " << query_res.getErr();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const AssetReply<QueryMatchSerializer> &asset : query_res.unpack()) {
|
||||
if (asset.matchValues<unordered_set<string>>(values)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// 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 "generic_rulebase/evaluators/trigger_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
string TriggerMatcher::ctx_key = "triggers";
|
||||
|
||||
TriggerMatcher::TriggerMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(TriggerMatcher::getName(), params.size(), 1, 1);
|
||||
trigger_id = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
TriggerMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<TriggerMatcher>();
|
||||
auto ac_bc_trigger_id_ctx = env->get<set<GenericConfigId>>("ac_trigger_id");
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Trying to match trigger for access control rule. ID: "
|
||||
<< trigger_id << ", Current set IDs: "
|
||||
<< makeSeparatedStr(ac_bc_trigger_id_ctx.ok() ? *ac_bc_trigger_id_ctx : set<GenericConfigId>(), ", ");
|
||||
if (ac_bc_trigger_id_ctx.ok()) {
|
||||
return ac_bc_trigger_id_ctx.unpack().count(trigger_id) > 0;
|
||||
}
|
||||
|
||||
auto bc_trigger_id_ctx = env->get<set<GenericConfigId>>(TriggerMatcher::ctx_key);
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Trying to match trigger. ID: "
|
||||
<< trigger_id << ", Current set IDs: "
|
||||
<< makeSeparatedStr(bc_trigger_id_ctx.ok() ? *bc_trigger_id_ctx : set<GenericConfigId>(), ", ");
|
||||
if (bc_trigger_id_ctx.ok() && bc_trigger_id_ctx.unpack().count(trigger_id) > 0 ) return true;
|
||||
|
||||
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
|
||||
return rule.ok() && rule.unpack().isTriggerActive(trigger_id);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// 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 "generic_rulebase/evaluators/zone_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/zone.h"
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "config.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string ZoneMatcher::ctx_key = "zone_id";
|
||||
|
||||
ZoneMatcher::ZoneMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(ZoneMatcher::getName(), params.size(), 1, 1);
|
||||
zone_id = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
ZoneMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<ZoneMatcher>();
|
||||
auto bc_zone_id_ctx = env->get<GenericConfigId>(ZoneMatcher::ctx_key);
|
||||
if (bc_zone_id_ctx.ok() && *bc_zone_id_ctx == zone_id) return true;
|
||||
|
||||
if (!getProfileAgentSettingWithDefault<bool>(false, "rulebase.enableQueryBasedMatch")) return false;
|
||||
|
||||
auto zone = getConfiguration<Zone>("rulebase", "zones");
|
||||
return zone.ok() && zone.unpack().getId() == zone_id;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
// 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 "generic_rulebase/generic_rulebase.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "generic_rulebase/evaluators/trigger_eval.h"
|
||||
#include "generic_rulebase/evaluators/practice_eval.h"
|
||||
#include "generic_rulebase/evaluators/parameter_eval.h"
|
||||
#include "generic_rulebase/evaluators/zone_eval.h"
|
||||
#include "generic_rulebase/evaluators/asset_eval.h"
|
||||
#include "generic_rulebase/evaluators/query_eval.h"
|
||||
#include "generic_rulebase/evaluators/connection_eval.h"
|
||||
#include "generic_rulebase/evaluators/http_transaction_data_eval.h"
|
||||
#include "generic_rulebase/zone.h"
|
||||
#include "generic_rulebase/triggers_config.h"
|
||||
#include "singleton.h"
|
||||
#include "common.h"
|
||||
#include "debug.h"
|
||||
#include "cache.h"
|
||||
#include "config.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
class GenericRulebase::Impl : Singleton::Provide<I_GenericRulebase>::From<GenericRulebase>
|
||||
{
|
||||
public:
|
||||
void init() {}
|
||||
void fini() {}
|
||||
|
||||
void preload();
|
||||
|
||||
Maybe<Zone, Config::Errors> getLocalZone() const override { return getZoneConfig(true); }
|
||||
Maybe<Zone, Config::Errors> getOtherZone() const override { return getZoneConfig(false); }
|
||||
|
||||
set<ParameterBehavior> getBehavior(const ParameterKeyValues &key_value_pairs) const override;
|
||||
|
||||
private:
|
||||
Maybe<Zone, Config::Errors>
|
||||
getZoneConfig(bool is_local_zone) const
|
||||
{
|
||||
ScopedContext asset_location_ctx;
|
||||
asset_location_ctx.registerValue<bool>("is local asset", is_local_zone);
|
||||
return getConfiguration<Zone>("rulebase", "zones");
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
GenericRulebase::Impl::preload()
|
||||
{
|
||||
addMatcher<TriggerMatcher>();
|
||||
addMatcher<PracticeMatcher>();
|
||||
addMatcher<ParameterMatcher>();
|
||||
addMatcher<ZoneMatcher>();
|
||||
addMatcher<AssetMatcher>();
|
||||
addMatcher<QueryMatcher>();
|
||||
addMatcher<IpAddressMatcher>();
|
||||
addMatcher<SourceIpMatcher>();
|
||||
addMatcher<DestinationIpMatcher>();
|
||||
addMatcher<SourcePortMatcher>();
|
||||
addMatcher<ListeningPortMatcher>();
|
||||
addMatcher<IpProtocolMatcher>();
|
||||
addMatcher<UrlMatcher>();
|
||||
addMatcher<EqualHost>();
|
||||
addMatcher<WildcardHost>();
|
||||
addMatcher<EqualListeningIP>();
|
||||
addMatcher<EqualListeningPort>();
|
||||
addMatcher<BeginWithUri>();
|
||||
BasicRuleConfig::preload();
|
||||
LogTriggerConf::preload();
|
||||
ParameterException::preload();
|
||||
registerExpectedConfiguration<Zone>("rulebase", "zones");
|
||||
registerExpectedConfigFile("zones", Config::ConfigFileType::Policy);
|
||||
registerExpectedConfigFile("triggers", Config::ConfigFileType::Policy);
|
||||
registerExpectedConfigFile("rules", Config::ConfigFileType::Policy);
|
||||
registerExpectedConfigFile("parameters", Config::ConfigFileType::Policy);
|
||||
registerExpectedConfigFile("exceptions", Config::ConfigFileType::Policy);
|
||||
|
||||
}
|
||||
|
||||
set<ParameterBehavior>
|
||||
GenericRulebase::Impl::getBehavior(const ParameterKeyValues &key_value_pairs) const
|
||||
{
|
||||
auto &exceptions = getConfiguration<ParameterException>("rulebase", "exception");
|
||||
|
||||
if (!exceptions.ok()) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Could not find any exception with the current rule's context";
|
||||
return {};
|
||||
}
|
||||
return (*exceptions).getBehavior(key_value_pairs);
|
||||
}
|
||||
|
||||
GenericRulebase::GenericRulebase() : Component("GenericRulebase"), pimpl(make_unique<Impl>()) {}
|
||||
|
||||
GenericRulebase::~GenericRulebase() {}
|
||||
|
||||
void
|
||||
GenericRulebase::init()
|
||||
{
|
||||
pimpl->init();
|
||||
}
|
||||
|
||||
void
|
||||
GenericRulebase::fini()
|
||||
{
|
||||
pimpl->fini();
|
||||
}
|
||||
|
||||
void
|
||||
GenericRulebase::preload()
|
||||
{
|
||||
pimpl->preload();
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
// 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 "generic_rulebase/generic_rulebase_context.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "context.h"
|
||||
#include "config.h"
|
||||
#include "generic_rulebase/evaluators/trigger_eval.h"
|
||||
#include "generic_rulebase/evaluators/parameter_eval.h"
|
||||
#include "generic_rulebase/evaluators/practice_eval.h"
|
||||
#include "generic_rulebase/evaluators/zone_eval.h"
|
||||
#include "generic_rulebase/evaluators/asset_eval.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<typename Configs>
|
||||
set<GenericConfigId>
|
||||
extractIds(const vector<Configs> &configurations)
|
||||
{
|
||||
set<GenericConfigId> ids;
|
||||
for (const Configs &conf : configurations) {
|
||||
ids.insert(conf.getId());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
void
|
||||
GenericRulebaseContext::activate(const BasicRuleConfig &rule)
|
||||
{
|
||||
switch(registration_state) {
|
||||
case RuleRegistrationState::UNINITIALIZED: {
|
||||
registration_state = RuleRegistrationState::REGISTERED;
|
||||
ctx.registerValue<set<GenericConfigId>>(
|
||||
TriggerMatcher::ctx_key,
|
||||
extractIds<RuleTrigger>(rule.getTriggers())
|
||||
);
|
||||
ctx.registerValue<set<GenericConfigId>>(
|
||||
PracticeMatcher::ctx_key,
|
||||
extractIds<RulePractice>(rule.getPractices())
|
||||
);
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Activating current practices. Current practice IDs: "
|
||||
<< makeSeparatedStr(extractIds<RulePractice>(rule.getPractices()), ", ");
|
||||
|
||||
ctx.registerValue<set<GenericConfigId>>(
|
||||
ParameterMatcher::ctx_key,
|
||||
extractIds<RuleParameter>(rule.getParameters())
|
||||
);
|
||||
ctx.registerValue<GenericConfigId>(
|
||||
ZoneMatcher::ctx_key,
|
||||
rule.getZoneId()
|
||||
);
|
||||
ctx.registerValue<GenericConfigId>(
|
||||
AssetMatcher::ctx_key,
|
||||
rule.getAssetId()
|
||||
);
|
||||
ctx.activate();
|
||||
break;
|
||||
}
|
||||
case RuleRegistrationState::REGISTERED: {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Activating registered rule values";
|
||||
ctx.activate();
|
||||
break;
|
||||
}
|
||||
case RuleRegistrationState::UNREGISTERED: {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Failed to register rule values";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericRulebaseContext::activate()
|
||||
{
|
||||
switch(registration_state) {
|
||||
case RuleRegistrationState::UNINITIALIZED: {
|
||||
auto maybe_rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
|
||||
if (!maybe_rule.ok()) {
|
||||
registration_state = RuleRegistrationState::UNREGISTERED;
|
||||
return;
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Registering new rule values";
|
||||
activate(maybe_rule.unpack());
|
||||
registration_state = RuleRegistrationState::REGISTERED;
|
||||
break;
|
||||
}
|
||||
case RuleRegistrationState::REGISTERED: {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Activating registered rule values";
|
||||
ctx.activate();
|
||||
break;
|
||||
}
|
||||
case RuleRegistrationState::UNREGISTERED: {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Failed to register rule values";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,347 +0,0 @@
|
||||
// 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 "generic_rulebase/match_query.h"
|
||||
|
||||
#include "cereal/types/set.hpp"
|
||||
|
||||
#include "generic_rulebase/generic_rulebase_utils.h"
|
||||
#include "config.h"
|
||||
#include "ip_utilities.h"
|
||||
#include "agent_core_utilities.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const unordered_map<string, MatchQuery::MatchType> string_to_match_type = {
|
||||
{ "condition", MatchQuery::MatchType::Condition },
|
||||
{ "operator", MatchQuery::MatchType::Operator }
|
||||
};
|
||||
|
||||
static const unordered_map<string, MatchQuery::Operators> string_to_operator = {
|
||||
{ "and", MatchQuery::Operators::And },
|
||||
{ "or", MatchQuery::Operators::Or }
|
||||
};
|
||||
|
||||
static const unordered_map<string, MatchQuery::Conditions> string_to_condition = {
|
||||
{ "equals", MatchQuery::Conditions::Equals },
|
||||
{ "not-equals", MatchQuery::Conditions::NotEquals },
|
||||
{ "not equals", MatchQuery::Conditions::NotEquals },
|
||||
{ "in", MatchQuery::Conditions::In },
|
||||
{ "not-in", MatchQuery::Conditions::NotIn },
|
||||
{ "not in", MatchQuery::Conditions::NotIn },
|
||||
{ "exist", MatchQuery::Conditions::Exist }
|
||||
};
|
||||
|
||||
static const string ip_addr_type_name = "IP address";
|
||||
static const string port_type_name = "port";
|
||||
static const string ip_proto_type_name = "IP protocol";
|
||||
|
||||
static const unordered_map<string, MatchQuery::StaticKeys> string_to_key = {
|
||||
{ "sourceIP", MatchQuery::StaticKeys::SrcIpAddress },
|
||||
{ "sourceIpAddr", MatchQuery::StaticKeys::SrcIpAddress },
|
||||
{ "destinationIP", MatchQuery::StaticKeys::DstIpAddress },
|
||||
{ "destinationIpAddr", MatchQuery::StaticKeys::DstIpAddress },
|
||||
{ "ipAddress", MatchQuery::StaticKeys::IpAddress },
|
||||
{ "sourcePort", MatchQuery::StaticKeys::SrcPort },
|
||||
{ "listeningPort", MatchQuery::StaticKeys::ListeningPort },
|
||||
{ "ipProtocol", MatchQuery::StaticKeys::IpProtocol },
|
||||
{ "domain", MatchQuery::StaticKeys::Domain }
|
||||
};
|
||||
|
||||
MatchQuery::MatchQuery(const string &match) : is_specific_label(false), is_ignore_keyword(false)
|
||||
{
|
||||
try {
|
||||
stringstream ss;
|
||||
ss.str(match);
|
||||
cereal::JSONInputArchive archive_in(ss);
|
||||
load(archive_in);
|
||||
} catch (const exception &e) {
|
||||
dbgWarning(D_RULEBASE_CONFIG)
|
||||
<< "Unable to load match query JSON. JSON content: "
|
||||
<< match
|
||||
<< ", Error: "
|
||||
<< e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MatchQuery::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
string type_as_string;
|
||||
archive_in(cereal::make_nvp("type", type_as_string));
|
||||
|
||||
string op_as_string;
|
||||
archive_in(cereal::make_nvp("op", op_as_string));
|
||||
|
||||
auto maybe_type = string_to_match_type.find(type_as_string);
|
||||
if (maybe_type == string_to_match_type.end()) {
|
||||
reportConfigurationError("Illegal Zone match query type. Provided type in configuration: " + type_as_string);
|
||||
}
|
||||
|
||||
type = maybe_type->second;
|
||||
switch (type) {
|
||||
case (MatchType::Condition): {
|
||||
auto maybe_condition = string_to_condition.find(op_as_string);
|
||||
if (maybe_condition == string_to_condition.end()) {
|
||||
reportConfigurationError(
|
||||
"Illegal op provided for condition. Provided op in configuration: " +
|
||||
op_as_string
|
||||
);
|
||||
}
|
||||
condition_type = maybe_condition->second;
|
||||
operator_type = Operators::None;
|
||||
archive_in(cereal::make_nvp("key", key));
|
||||
key_type = getKeyByName(key);
|
||||
if (key_type == StaticKeys::NotStatic) {
|
||||
if (key.rfind("containerLabels.", 0) == 0) {
|
||||
is_specific_label = true;
|
||||
} else {
|
||||
is_specific_label = false;
|
||||
}
|
||||
}
|
||||
is_ignore_keyword = (key == "indicator");
|
||||
|
||||
if (condition_type != Conditions::Exist) {
|
||||
archive_in(cereal::make_nvp("value", value));
|
||||
for(const auto &val: value) {
|
||||
if (isKeyTypeIp()) {
|
||||
auto ip_range = IPUtilities::createRangeFromString<IPRange, IpAddress>(val, ip_addr_type_name);
|
||||
if (ip_range.ok()) {
|
||||
ip_addr_value.push_back(ip_range.unpack());
|
||||
} else {
|
||||
dbgWarning(D_RULEBASE_CONFIG)
|
||||
<< "Failed to parse IP address range. Error: "
|
||||
<< ip_range.getErr();
|
||||
}
|
||||
} else if (isKeyTypePort()) {
|
||||
auto port_range = IPUtilities::createRangeFromString<PortsRange, uint16_t>(
|
||||
val,
|
||||
port_type_name
|
||||
);
|
||||
if (port_range.ok()) {
|
||||
port_value.push_back(port_range.unpack());
|
||||
} else {
|
||||
dbgWarning(D_RULEBASE_CONFIG)
|
||||
<< "Failed to parse port range. Error: "
|
||||
<< port_range.getErr();
|
||||
}
|
||||
} else if (isKeyTypeProtocol()) {
|
||||
auto proto_range = IPUtilities::createRangeFromString<IpProtoRange, uint8_t>(
|
||||
val,
|
||||
ip_proto_type_name
|
||||
);
|
||||
if (proto_range.ok()) {
|
||||
ip_proto_value.push_back(proto_range.unpack());
|
||||
} else {
|
||||
dbgWarning(D_RULEBASE_CONFIG)
|
||||
<< "Failed to parse IP protocol range. Error: "
|
||||
<< proto_range.getErr();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
regex_values.insert(boost::regex(val));
|
||||
} catch (const exception &e) {
|
||||
dbgDebug(D_RULEBASE_CONFIG) << "Failed to compile regex. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
first_value = *(value.begin());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (MatchType::Operator): {
|
||||
auto maybe_operator = string_to_operator.find(op_as_string);
|
||||
if (maybe_operator == string_to_operator.end()) {
|
||||
reportConfigurationError(
|
||||
"Illegal op provided for operator. Provided op in configuration: " +
|
||||
op_as_string
|
||||
);
|
||||
}
|
||||
operator_type = maybe_operator->second;
|
||||
condition_type = Conditions::None;
|
||||
archive_in(cereal::make_nvp("items", items));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MatchQuery::StaticKeys
|
||||
MatchQuery::getKeyByName(const string &key_type_name)
|
||||
{
|
||||
auto key = string_to_key.find(key_type_name);
|
||||
if (key == string_to_key.end()) return StaticKeys::NotStatic;
|
||||
return key->second;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::isKeyTypeIp() const
|
||||
{
|
||||
return (key_type >= StaticKeys::IpAddress && key_type <= StaticKeys::DstIpAddress);
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::isKeyTypePort() const
|
||||
{
|
||||
return (key_type == StaticKeys::SrcPort || key_type == StaticKeys::ListeningPort);
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::isKeyTypeProtocol() const
|
||||
{
|
||||
return (key_type == StaticKeys::IpProtocol);
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::isKeyTypeDomain() const
|
||||
{
|
||||
return (key_type == StaticKeys::Domain);
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::isKeyTypeSpecificLabel() const
|
||||
{
|
||||
return is_specific_label;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::isKeyTypeStatic() const
|
||||
{
|
||||
return (key_type != StaticKeys::NotStatic);
|
||||
}
|
||||
|
||||
set<string>
|
||||
MatchQuery::getAllKeys() const
|
||||
{
|
||||
set<string> keys;
|
||||
if (type == MatchType::Condition) {
|
||||
if (!key.empty()) keys.insert(key);
|
||||
return keys;
|
||||
}
|
||||
|
||||
for (const MatchQuery &inner_match: items) {
|
||||
set<string> iner_keys = inner_match.getAllKeys();
|
||||
keys.insert(iner_keys.begin(), iner_keys.end());
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributes(
|
||||
const unordered_map<string, set<string>> &key_value_pairs,
|
||||
set<string> &matched_override_keywords ) const
|
||||
{
|
||||
|
||||
if (type == MatchType::Condition) {
|
||||
auto key_value_pair = key_value_pairs.find(key);
|
||||
if (key_value_pair == key_value_pairs.end()) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ignoring irrelevant key: " << key;
|
||||
return false;
|
||||
}
|
||||
return matchAttributes(key_value_pair->second, matched_override_keywords);
|
||||
} else if (type == MatchType::Operator && operator_type == Operators::And) {
|
||||
for (const MatchQuery &inner_match: items) {
|
||||
if (!inner_match.matchAttributes(key_value_pairs, matched_override_keywords)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (type == MatchType::Operator && operator_type == Operators::Or) {
|
||||
// With 'or' condition, evaluate matched override keywords first and add the ones that were fully matched
|
||||
set<string> inner_override_keywords;
|
||||
bool res = false;
|
||||
for (const MatchQuery &inner_match: items) {
|
||||
inner_override_keywords.clear();
|
||||
if (inner_match.matchAttributes(key_value_pairs, inner_override_keywords)) {
|
||||
matched_override_keywords.insert(inner_override_keywords.begin(), inner_override_keywords.end());
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Unsupported match query type";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MatchQuery::MatchResult
|
||||
MatchQuery::getMatch( const unordered_map<string, set<string>> &key_value_pairs) const
|
||||
{
|
||||
MatchQuery::MatchResult matches;
|
||||
matches.matched_keywords = make_shared<set<string>>();
|
||||
matches.is_match = matchAttributes(key_value_pairs, *matches.matched_keywords);
|
||||
return matches;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributes(
|
||||
const unordered_map<string, set<string>> &key_value_pairs) const
|
||||
{
|
||||
return getMatch(key_value_pairs).is_match;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributes(
|
||||
const set<string> &values,
|
||||
set<string> &matched_override_keywords) const
|
||||
{
|
||||
auto &type = condition_type;
|
||||
bool negate = type == MatchQuery::Conditions::NotEquals || type == MatchQuery::Conditions::NotIn;
|
||||
bool match = isRegEx() ? matchAttributesRegEx(values, matched_override_keywords) : matchAttributesString(values);
|
||||
return negate ? !match : match;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributesRegEx(
|
||||
const set<string> &values,
|
||||
set<string> &matched_override_keywords) const
|
||||
{
|
||||
bool res = false;
|
||||
boost::cmatch value_matcher;
|
||||
for (const boost::regex &val_regex : regex_values) {
|
||||
for (const string &requested_match_value : values) {
|
||||
if (NGEN::Regex::regexMatch(
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
requested_match_value.c_str(),
|
||||
value_matcher,
|
||||
val_regex))
|
||||
{
|
||||
res = true;
|
||||
if (is_ignore_keyword) {
|
||||
matched_override_keywords.insert(requested_match_value);
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributesString(const set<string> &values) const
|
||||
{
|
||||
for (const string &requested_value : values) {
|
||||
if (value.find(requested_value) != value.end()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::isRegEx() const
|
||||
{
|
||||
return key != "protectionName";
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
// 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 "generic_rulebase/parameters_config.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool ParameterException::is_geo_location_exception_exists(false);
|
||||
bool ParameterException::is_geo_location_exception_being_loaded(false);
|
||||
|
||||
void
|
||||
ParameterOverrides::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseJSONKey<vector<ParsedBehavior>>("parsedBehavior", parsed_behaviors, archive_in);
|
||||
}
|
||||
|
||||
void
|
||||
ParameterTrustedSources::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseJSONKey<uint>("numOfSources", num_of_sources, archive_in);
|
||||
parseJSONKey<vector<SourcesIdentifier>>("sourcesIdentifiers", sources_identidiers, archive_in);
|
||||
}
|
||||
|
||||
void
|
||||
ParameterBehavior::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
string key_string;
|
||||
string val_string;
|
||||
parseJSONKey<string>("id", id, archive_in);
|
||||
parseJSONKey<string>("key", key_string, archive_in);
|
||||
parseJSONKey<string>("value", val_string, archive_in);
|
||||
if (string_to_behavior_key.find(key_string) == string_to_behavior_key.end()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Unsupported behavior key: " << key_string;
|
||||
return;
|
||||
}
|
||||
key = string_to_behavior_key.at(key_string);
|
||||
|
||||
if (string_to_behavior_val.find(val_string) == string_to_behavior_val.end()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Unsupported behavior value: " << val_string;
|
||||
return;
|
||||
}
|
||||
value = string_to_behavior_val.at(val_string);
|
||||
}
|
||||
|
||||
void
|
||||
ParameterAntiBot::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseJSONKey<vector<string>>("injected", injected, archive_in);
|
||||
parseJSONKey<vector<string>>("validated", validated, archive_in);
|
||||
}
|
||||
|
||||
void
|
||||
ParameterOAS::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseJSONKey<string>("value", value, archive_in);
|
||||
}
|
||||
|
||||
void
|
||||
ParameterException::MatchBehaviorPair::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseJSONKey<MatchQuery>("match", match, archive_in);
|
||||
parseJSONKey<ParameterBehavior>("behavior", behavior, archive_in);
|
||||
}
|
||||
|
||||
void
|
||||
ParameterException::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
try {
|
||||
archive_in(
|
||||
cereal::make_nvp("match", match),
|
||||
cereal::make_nvp("behavior", behavior)
|
||||
);
|
||||
} catch (...) {
|
||||
parseJSONKey<vector<MatchBehaviorPair>>("exceptions", match_queries, archive_in);
|
||||
}
|
||||
|
||||
function<bool(const MatchQuery &)> isGeoLocationExists =
|
||||
[&](const MatchQuery &query)
|
||||
{
|
||||
if (query.getKey() == "countryCode" || query.getKey() == "countryName") {
|
||||
is_geo_location_exception_being_loaded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const MatchQuery &query_item : query.getItems()) {
|
||||
if (isGeoLocationExists(query_item)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
if (isGeoLocationExists(match)) return;
|
||||
for (const MatchBehaviorPair &match_query : match_queries) {
|
||||
if (isGeoLocationExists(match_query.match)) return;
|
||||
}
|
||||
}
|
||||
|
||||
set<ParameterBehavior>
|
||||
ParameterException::getBehavior(
|
||||
const unordered_map<string, set<string>> &key_value_pairs,
|
||||
set<string> &matched_override_keywords) const
|
||||
{
|
||||
set<ParameterBehavior> matched_behaviors;
|
||||
|
||||
matched_override_keywords.clear();
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Matching exception";
|
||||
for (const MatchBehaviorPair &match_behavior_pair: match_queries) {
|
||||
MatchQuery::MatchResult match_res = match_behavior_pair.match.getMatch(key_value_pairs);
|
||||
if (match_res.is_match) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception from a list of matches.";
|
||||
// When matching indicators with action=ignore, we expect no behavior override.
|
||||
// Instead, a matched keywords list should be returned which will be later removed from score calculation
|
||||
if (match_res.matched_keywords->size() > 0 && match_behavior_pair.behavior == action_ignore) {
|
||||
matched_override_keywords.insert(match_res.matched_keywords->begin(),
|
||||
match_res.matched_keywords->end());
|
||||
} else {
|
||||
matched_behaviors.insert(match_behavior_pair.behavior);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match_queries.empty()) {
|
||||
MatchQuery::MatchResult match_res = match.getMatch(key_value_pairs);
|
||||
if (match_res.is_match) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
|
||||
// When matching indicators with action=ignore, we expect no behavior override.
|
||||
// Instead, a matched keywords list should be returned which will be later removed from score calculation
|
||||
if (match_res.matched_keywords->size() > 0 && behavior == action_ignore) {
|
||||
matched_override_keywords.insert(match_res.matched_keywords->begin(),
|
||||
match_res.matched_keywords->end());
|
||||
} else {
|
||||
matched_behaviors.insert(behavior);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matched_behaviors;
|
||||
}
|
||||
|
||||
set<ParameterBehavior>
|
||||
ParameterException::getBehavior(const unordered_map<string, set<string>> &key_value_pairs) const
|
||||
{
|
||||
set<string> keywords;
|
||||
return getBehavior(key_value_pairs, keywords);
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
// 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 "generic_rulebase/rulebase_config.h"
|
||||
|
||||
#include "telemetry.h"
|
||||
#include "config.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
set<string> BasicRuleConfig::assets_ids{};
|
||||
set<string> BasicRuleConfig::assets_ids_aggregation{};
|
||||
|
||||
void
|
||||
BasicRuleConfig::load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
parseJSONKey<vector<RulePractice>>("practices", practices, ar);
|
||||
parseJSONKey<vector<RuleTrigger>>("triggers", triggers, ar);
|
||||
parseJSONKey<vector<RuleParameter>>("parameters", parameters, ar);
|
||||
parseJSONKey<uint8_t>("priority", priority, ar);
|
||||
parseJSONKey<string>("ruleId", rule_id, ar);
|
||||
parseJSONKey<string>("ruleName", rule_name, ar);
|
||||
parseJSONKey<string>("assetId", asset_id, ar);
|
||||
parseJSONKey<string>("assetName", asset_name, ar);
|
||||
parseJSONKey<string>("zoneId", zone_id, ar);
|
||||
parseJSONKey<string>("zoneName", zone_name, ar);
|
||||
|
||||
assets_ids_aggregation.insert(asset_id);
|
||||
}
|
||||
|
||||
void
|
||||
BasicRuleConfig::updateCountMetric()
|
||||
{
|
||||
BasicRuleConfig::assets_ids = BasicRuleConfig::assets_ids_aggregation;
|
||||
AssetCountEvent(AssetType::ALL, BasicRuleConfig::assets_ids.size()).notify();
|
||||
}
|
||||
|
||||
bool
|
||||
BasicRuleConfig::isPracticeActive(const string &practice_id) const
|
||||
{
|
||||
for (auto practice: practices) {
|
||||
if (practice.getId() == practice_id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BasicRuleConfig::isTriggerActive(const string &trigger_id) const
|
||||
{
|
||||
for (auto trigger: triggers) {
|
||||
if (trigger.getId() == trigger_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BasicRuleConfig::isParameterActive(const string ¶meter_id) const
|
||||
{
|
||||
for (auto param: parameters) {
|
||||
if (param.getId() == parameter_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
// 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 <string>
|
||||
#include <map>
|
||||
|
||||
#include "generic_rulebase/triggers_config.h"
|
||||
#include "generic_rulebase/generic_rulebase_utils.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
WebTriggerConf::WebTriggerConf() : response_title(""), response_body(""), response_code(0) {}
|
||||
WebTriggerConf::WebTriggerConf(const string &title, const string &body, uint code)
|
||||
:
|
||||
response_title(title),
|
||||
response_body(body),
|
||||
response_code(code)
|
||||
{}
|
||||
|
||||
WebTriggerConf WebTriggerConf::default_trigger_conf = WebTriggerConf(
|
||||
"Attack blocked by web application protection", // title
|
||||
"Check Point's <b>Application Security</b> has detected an attack and blocked it.", // body
|
||||
403
|
||||
);
|
||||
|
||||
void
|
||||
WebTriggerConf::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
try {
|
||||
parseJSONKey<string>("details level", details_level, archive_in);
|
||||
if (details_level == "Redirect") {
|
||||
parseJSONKey<string>("redirect URL", redirect_url, archive_in);
|
||||
parseJSONKey<bool>("xEventId", add_event_id_to_header, archive_in);
|
||||
parseJSONKey<bool>("eventIdInHeader", add_event_id_to_header, archive_in);
|
||||
return;
|
||||
}
|
||||
parseJSONKey<uint>("response code", response_code, archive_in);
|
||||
if (response_code < 100 || response_code > 599) {
|
||||
throw cereal::Exception(
|
||||
"illegal web trigger response code: " +
|
||||
to_string(response_code) +
|
||||
" is out of range (100-599)"
|
||||
);
|
||||
}
|
||||
|
||||
if (details_level == "Response Code") return;
|
||||
|
||||
parseJSONKey<string>("response body", response_body, archive_in);
|
||||
parseJSONKey<string>("response title", response_title, archive_in);
|
||||
} catch (const exception &e) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to parse the web trigger configuration: '" << e.what() << "'";
|
||||
archive_in.setNextName(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WebTriggerConf::operator==(const WebTriggerConf &other) const
|
||||
{
|
||||
return
|
||||
response_code == other.response_code &&
|
||||
response_title == other.response_title &&
|
||||
response_body == other.response_body;
|
||||
}
|
||||
|
||||
LogTriggerConf::LogTriggerConf(string trigger_name, bool log_detect, bool log_prevent) : name(trigger_name)
|
||||
{
|
||||
if (log_detect) should_log_on_detect.setAll();
|
||||
if (log_prevent) should_log_on_prevent.setAll();
|
||||
active_streams.setFlag(ReportIS::StreamType::JSON_FOG);
|
||||
active_streams.setFlag(ReportIS::StreamType::JSON_LOG_FILE);
|
||||
}
|
||||
|
||||
ReportIS::Severity
|
||||
LogTriggerConf::getSeverity(bool is_action_drop_or_prevent) const
|
||||
{
|
||||
return is_action_drop_or_prevent ? ReportIS::Severity::MEDIUM : ReportIS::Severity::LOW;
|
||||
}
|
||||
|
||||
ReportIS::Priority
|
||||
LogTriggerConf::getPriority(bool is_action_drop_or_prevent) const
|
||||
{
|
||||
return is_action_drop_or_prevent ? ReportIS::Priority::HIGH : ReportIS::Priority::MEDIUM;
|
||||
}
|
||||
|
||||
Flags<ReportIS::StreamType>
|
||||
LogTriggerConf::getStreams(SecurityType security_type, bool is_action_drop_or_prevent) const
|
||||
{
|
||||
if (is_action_drop_or_prevent && should_log_on_prevent.isSet(security_type)) return active_streams;
|
||||
if (!is_action_drop_or_prevent && should_log_on_detect.isSet(security_type)) return active_streams;
|
||||
|
||||
return Flags<ReportIS::StreamType>();
|
||||
}
|
||||
|
||||
Flags<ReportIS::Enreachments>
|
||||
LogTriggerConf::getEnrechments(SecurityType security_type) const
|
||||
{
|
||||
Flags<ReportIS::Enreachments> enreachments;
|
||||
|
||||
if (log_geo_location.isSet(security_type)) enreachments.setFlag(ReportIS::Enreachments::GEOLOCATION);
|
||||
if (should_format_output) enreachments.setFlag(ReportIS::Enreachments::BEAUTIFY_OUTPUT);
|
||||
|
||||
return enreachments;
|
||||
}
|
||||
|
||||
template <typename EnumClass>
|
||||
static void
|
||||
setTriggersFlag(const string &key, cereal::JSONInputArchive &ar, EnumClass flag, Flags<EnumClass> &flags)
|
||||
{
|
||||
bool value = false;
|
||||
parseJSONKey<bool>(key, value, ar);
|
||||
if (value) flags.setFlag(flag);
|
||||
}
|
||||
|
||||
static void
|
||||
setLogConfiguration(
|
||||
const ReportIS::StreamType &log_type,
|
||||
const string &log_server_url = "",
|
||||
const string &protocol = ""
|
||||
)
|
||||
{
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "log server url:" << log_server_url;
|
||||
if (log_server_url != "" && protocol != "") {
|
||||
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url, protocol);
|
||||
} else {
|
||||
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type);
|
||||
}
|
||||
}
|
||||
|
||||
static string
|
||||
parseProtocolWithDefault(
|
||||
const std::string &default_value,
|
||||
const std::string &key_name,
|
||||
cereal::JSONInputArchive &archive_in
|
||||
)
|
||||
{
|
||||
string value;
|
||||
try {
|
||||
archive_in(cereal::make_nvp(key_name, value));
|
||||
} catch (const cereal::Exception &e) {
|
||||
return default_value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
|
||||
{
|
||||
try {
|
||||
parseJSONKey<string>("triggerName", name, archive_in);
|
||||
parseJSONKey<string>("verbosity", verbosity, archive_in);
|
||||
parseJSONKey<string>("urlForSyslog", url_for_syslog, archive_in);
|
||||
parseJSONKey<string>("urlForCef", url_for_cef, archive_in);
|
||||
parseJSONKey<string>("syslogProtocol", syslog_protocol, archive_in);
|
||||
syslog_protocol = parseProtocolWithDefault("UDP", "syslogProtocol", archive_in);
|
||||
cef_protocol = parseProtocolWithDefault("UDP", "cefProtocol", archive_in);
|
||||
|
||||
setTriggersFlag("webBody", archive_in, WebLogFields::webBody, log_web_fields);
|
||||
setTriggersFlag("webHeaders", archive_in, WebLogFields::webHeaders, log_web_fields);
|
||||
setTriggersFlag("webRequests", archive_in, WebLogFields::webRequests, log_web_fields);
|
||||
setTriggersFlag("webUrlPath", archive_in, WebLogFields::webUrlPath, log_web_fields);
|
||||
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("logToK8sService", archive_in, ReportIS::StreamType::JSON_K8S_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);
|
||||
setTriggersFlag("acDrop", archive_in, SecurityType::AccessControl, should_log_on_prevent);
|
||||
setTriggersFlag("tpDetect", archive_in, SecurityType::ThreatPrevention, should_log_on_detect);
|
||||
setTriggersFlag("tpPrevent", archive_in, SecurityType::ThreatPrevention, should_log_on_prevent);
|
||||
setTriggersFlag("complianceWarnings", archive_in, SecurityType::Compliance, should_log_on_detect);
|
||||
setTriggersFlag("complianceViolations", archive_in, SecurityType::Compliance, should_log_on_prevent);
|
||||
setTriggersFlag("acLogGeoLocation", archive_in, SecurityType::AccessControl, log_geo_location);
|
||||
setTriggersFlag("tpLogGeoLocation", archive_in, SecurityType::ThreatPrevention, log_geo_location);
|
||||
setTriggersFlag("complianceLogGeoLocation", archive_in, SecurityType::Compliance, log_geo_location);
|
||||
|
||||
bool extend_logging = false;
|
||||
parseJSONKey<bool>("extendLogging", extend_logging, archive_in);
|
||||
if (extend_logging) {
|
||||
setTriggersFlag("responseCode", archive_in, WebLogFields::responseCode, log_web_fields);
|
||||
setTriggersFlag("responseBody", archive_in, WebLogFields::responseBody, log_web_fields);
|
||||
|
||||
string severity;
|
||||
static const map<string, extendLoggingSeverity> extend_logging_severity_strings = {
|
||||
{"High", extendLoggingSeverity::High},
|
||||
{"Critical", extendLoggingSeverity::Critical}
|
||||
};
|
||||
parseJSONKey<string>("extendLoggingMinSeverity", severity, archive_in);
|
||||
auto extended_severity = extend_logging_severity_strings.find(severity);
|
||||
if (extended_severity != extend_logging_severity_strings.end()) {
|
||||
extend_logging_severity = extended_severity->second;
|
||||
} else {
|
||||
dbgWarning(D_RULEBASE_CONFIG)
|
||||
<< "Failed to parse the extendLoggingMinSeverityfield: '"
|
||||
<< severity
|
||||
<< "'";
|
||||
}
|
||||
}
|
||||
|
||||
for (ReportIS::StreamType log_stream : makeRange<ReportIS::StreamType>()) {
|
||||
if (!active_streams.isSet(log_stream)) continue;
|
||||
switch (log_stream) {
|
||||
case ReportIS::StreamType::JSON_DEBUG:
|
||||
setLogConfiguration(ReportIS::StreamType::JSON_DEBUG);
|
||||
break;
|
||||
case ReportIS::StreamType::JSON_FOG:
|
||||
setLogConfiguration(ReportIS::StreamType::JSON_FOG);
|
||||
break;
|
||||
case ReportIS::StreamType::JSON_LOG_FILE:
|
||||
setLogConfiguration(ReportIS::StreamType::JSON_LOG_FILE);
|
||||
break;
|
||||
case ReportIS::StreamType::JSON_K8S_SVC:
|
||||
setLogConfiguration(ReportIS::StreamType::JSON_K8S_SVC);
|
||||
break;
|
||||
case ReportIS::StreamType::SYSLOG:
|
||||
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog(), syslog_protocol);
|
||||
break;
|
||||
case ReportIS::StreamType::CEF:
|
||||
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef(), cef_protocol);
|
||||
break;
|
||||
case ReportIS::StreamType::NONE: break;
|
||||
case ReportIS::StreamType::COUNT: break;
|
||||
}
|
||||
}
|
||||
|
||||
parseJSONKey<bool>("formatLoggingOutput", should_format_output, archive_in);
|
||||
} catch (const exception &e) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to parse the log trigger configuration: '" << e.what() << "'";
|
||||
archive_in.setNextName(nullptr);
|
||||
}
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
// 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 "generic_rulebase/zone.h"
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const unordered_map<string, Zone::Direction> string_to_direction = {
|
||||
{ "to", Zone::Direction::To },
|
||||
{ "from", Zone::Direction::From },
|
||||
{ "bidirectional", Zone::Direction::Bidirectional }
|
||||
};
|
||||
|
||||
class AdjacentZone
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
string direction_as_string;
|
||||
archive_in(cereal::make_nvp("direction", direction_as_string));
|
||||
archive_in(cereal::make_nvp("zoneId", id));
|
||||
auto maybe_direction = string_to_direction.find(direction_as_string);
|
||||
if (maybe_direction == string_to_direction.end()) {
|
||||
reportConfigurationError(
|
||||
"Illegal direction provided for adjacency. Provided direction in configuration: " +
|
||||
direction_as_string
|
||||
);
|
||||
}
|
||||
dir = maybe_direction->second;
|
||||
}
|
||||
|
||||
pair<Zone::Direction, GenericConfigId> getValue() const { return make_pair(dir, id); }
|
||||
|
||||
private:
|
||||
Zone::Direction dir;
|
||||
GenericConfigId id;
|
||||
};
|
||||
|
||||
class TagsValues
|
||||
{
|
||||
public:
|
||||
static const string req_attrs_ctx_key;
|
||||
|
||||
TagsValues() {}
|
||||
|
||||
template <typename Archive>
|
||||
void
|
||||
serialize(Archive &ar)
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<Zone>();
|
||||
auto req_attrs = env->get<set<string>>(req_attrs_ctx_key);
|
||||
if (!req_attrs.ok()) return;
|
||||
|
||||
for (const string &req_attr : *req_attrs) {
|
||||
try {
|
||||
string data;
|
||||
ar(cereal::make_nvp(req_attr, data));
|
||||
dbgDebug(D_RULEBASE_CONFIG)
|
||||
<< "Found value for requested attribute. Tag: "
|
||||
<< req_attr
|
||||
<< ", Value: "
|
||||
<< data;
|
||||
|
||||
tags_set[req_attr].insert(data);
|
||||
} catch (const exception &e) {
|
||||
dbgDebug(D_RULEBASE_CONFIG) << "Could not find values for requested attribute. Tag: " << req_attr;
|
||||
ar.setNextName(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
matchValueByKey(const string &requested_key, const unordered_set<string> &possible_values) const
|
||||
{
|
||||
auto values = tags_set.find(requested_key);
|
||||
if (values == tags_set.end()) return false;
|
||||
|
||||
for (const string &val : possible_values) {
|
||||
if (values->second.count(val)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
insert(const TagsValues &other)
|
||||
{
|
||||
for (auto &single_tags_value : other.getData()) {
|
||||
tags_set[single_tags_value.first].insert(single_tags_value.second.begin(), single_tags_value.second.end());
|
||||
}
|
||||
}
|
||||
|
||||
const unordered_map<string, set<string>> & getData() const { return tags_set; }
|
||||
|
||||
private:
|
||||
unordered_map<string, set<string>> tags_set;
|
||||
};
|
||||
|
||||
const string TagsValues::req_attrs_ctx_key = "requested attributes key";
|
||||
|
||||
void
|
||||
Zone::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
archive_in(cereal::make_nvp("id", zone_id));
|
||||
archive_in(cereal::make_nvp("name", zone_name));
|
||||
vector<AdjacentZone> adjacency;
|
||||
try {
|
||||
archive_in(cereal::make_nvp("adjacentZones", adjacency));
|
||||
} catch (const cereal::Exception &) {
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "List of adjacentZones does not exist for current object. Zone id: "
|
||||
<< zone_id
|
||||
<< ", Zone name: "
|
||||
<< zone_name;
|
||||
|
||||
archive_in.setNextName(nullptr);
|
||||
}
|
||||
|
||||
for (const AdjacentZone &zone : adjacency) {
|
||||
adjacent_zones.push_back(zone.getValue());
|
||||
}
|
||||
|
||||
archive_in(cereal::make_nvp("match", match_query));
|
||||
|
||||
is_any =
|
||||
match_query.getType() == MatchQuery::MatchType::Condition &&
|
||||
match_query.getKey() == "any" &&
|
||||
match_query.getValue().count("any") > 0;
|
||||
|
||||
set<string> keys = match_query.getAllKeys();
|
||||
}
|
||||
|
||||
const string
|
||||
contextKeyToString(Context::MetaDataType type)
|
||||
{
|
||||
if (type == Context::MetaDataType::SubjectIpAddr || type == Context::MetaDataType::OtherIpAddr) return "ip";
|
||||
return Context::convertToString(type);
|
||||
}
|
||||
|
||||
bool
|
||||
Zone::contains(const Asset &asset)
|
||||
{
|
||||
QueryRequest request;
|
||||
|
||||
for (const auto &main_attr : asset.getAttrs()) {
|
||||
request.addCondition(Condition::EQUALS, contextKeyToString(main_attr.first), main_attr.second);
|
||||
}
|
||||
|
||||
ScopedContext req_attrs_key;
|
||||
req_attrs_key.registerValue<set<string>>(TagsValues::req_attrs_ctx_key, match_query.getAllKeys());
|
||||
|
||||
I_Intelligence_IS_V2 *intelligence = Singleton::Consume<I_Intelligence_IS_V2>::by<Zone>();
|
||||
auto query_res = intelligence->queryIntelligence<TagsValues>(request);
|
||||
if (!query_res.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to perform intelligence query. Error: " << query_res.getErr();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const AssetReply<TagsValues> &asset : query_res.unpack()) {
|
||||
TagsValues tag_values = asset.mergeReplyData();
|
||||
|
||||
if (match_query.matchAttributes(tag_values.getData())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
// 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 "generic_rulebase/zones_config.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "generic_rulebase/generic_rulebase_utils.h"
|
||||
#include "config.h"
|
||||
#include "ip_utilities.h"
|
||||
#include "connkey.h"
|
||||
#include "i_generic_rulebase.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
void
|
||||
ZonesConfig::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgFlow(D_RULEBASE_CONFIG) << "Saving active zones";
|
||||
set<string> used_zones;
|
||||
cereal::load(archive_in, used_zones);
|
||||
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Loading all zones";
|
||||
auto all_zones_maybe = getSetting<Zones>("rulebase", "zones");
|
||||
if (!all_zones_maybe.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to load zones";
|
||||
return;
|
||||
}
|
||||
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Creating cache of all zones by ID";
|
||||
map<GenericConfigId, Zone> all_zones;
|
||||
for (const auto &single_zone : all_zones_maybe.unpack().zones) {
|
||||
if (used_zones.count(single_zone.getId()) > 0 && single_zone.isAnyZone()) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Found used zone of type \"Any\": saving all zones as active zones";
|
||||
zones = all_zones_maybe.unpack().zones;
|
||||
return;
|
||||
}
|
||||
|
||||
dbgDebug(D_RULEBASE_CONFIG)
|
||||
<< "Adding specific zone to cache. Zone ID: "
|
||||
<< single_zone.getId()
|
||||
<< ", name: "
|
||||
<< single_zone.getName();
|
||||
all_zones.emplace(single_zone.getId(), single_zone);
|
||||
}
|
||||
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Creating list of active zones";
|
||||
map<GenericConfigId, Zone> active_zones_set;
|
||||
for (const auto &single_used_zone_id : used_zones) {
|
||||
const auto &found_zone = all_zones[single_used_zone_id];
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Adding zone to list of active zones. Zone ID: "
|
||||
<< single_used_zone_id
|
||||
<< ", zone name: "
|
||||
<< found_zone.getName();
|
||||
active_zones_set.emplace(found_zone.getId(), found_zone);
|
||||
|
||||
for (const auto &adjacent_zone : found_zone.getAdjacentZones()) {
|
||||
const auto &adjacent_zone_obj = all_zones[adjacent_zone.second];
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Adding adjacent zone to list of active zones. Zone ID: "
|
||||
<< adjacent_zone_obj.getId()
|
||||
<< ", zone name: "
|
||||
<< adjacent_zone_obj.getName();
|
||||
active_zones_set.emplace(adjacent_zone_obj.getId(), adjacent_zone_obj);
|
||||
}
|
||||
}
|
||||
|
||||
vector<GenericConfigId> implied_zones = {
|
||||
"impliedAzure",
|
||||
"impliedDNS",
|
||||
"impliedSSH",
|
||||
"impliedProxy",
|
||||
"impliedFog"
|
||||
};
|
||||
|
||||
GenericConfigId any_zone_id = "";
|
||||
for (const auto &single_zone : all_zones_maybe.unpack().zones) {
|
||||
if (single_zone.isAnyZone()) any_zone_id = single_zone.getId();
|
||||
}
|
||||
for (GenericConfigId &implied_id: implied_zones) {
|
||||
if (all_zones.find(implied_id) != all_zones.end()) {
|
||||
dbgDebug(D_RULEBASE_CONFIG) << "Adding implied zone to cache. Zone ID: " << implied_id;
|
||||
active_zones_set.emplace(implied_id, all_zones[implied_id]);
|
||||
if (any_zone_id != "" && active_zones_set.count(any_zone_id) == 0) {
|
||||
active_zones_set.emplace(any_zone_id, all_zones[any_zone_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &single_id_zone_pair : active_zones_set) {
|
||||
zones.push_back(single_id_zone_pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ZonesConfig::preload()
|
||||
{
|
||||
registerExpectedSetting<Zones>("rulebase", "zones");
|
||||
registerExpectedSetting<ZonesConfig>("rulebase", "usedZones");
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
include_directories(${CMAKE_SOURCE_DIR}/components/include)
|
||||
link_directories(${BOOST_ROOT}/lib)
|
||||
|
||||
add_unit_test(
|
||||
health_check_manager_ut
|
||||
"health_check_manager_ut.cc"
|
||||
"singleton;messaging;mainloop;health_check_manager;event_is;metric;-lboost_regex"
|
||||
)
|
||||
@@ -34,6 +34,7 @@ public:
|
||||
~DetailsResolver();
|
||||
|
||||
void preload() override;
|
||||
void init() override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "url_parser.h"
|
||||
#include "i_agent_details.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
#include "component.h"
|
||||
|
||||
@@ -32,6 +33,7 @@ class Downloader
|
||||
Singleton::Consume<I_Encryptor>,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_OrchestrationTools>,
|
||||
Singleton::Consume<I_Environment>,
|
||||
Singleton::Consume<I_UpdateCommunication>
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -15,7 +15,8 @@ class HttpGeoFilter
|
||||
public Component,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_GeoLocation>,
|
||||
Singleton::Consume<I_GenericRulebase>
|
||||
Singleton::Consume<I_GenericRulebase>,
|
||||
Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
HttpGeoFilter();
|
||||
|
||||
@@ -136,6 +136,7 @@ public:
|
||||
static const std::string req_body;
|
||||
static const std::string source_identifier;
|
||||
static const std::string proxy_ip_ctx;
|
||||
static const std::string xff_vals_ctx;
|
||||
|
||||
static const CompressionType default_response_content_encoding;
|
||||
|
||||
|
||||
@@ -29,7 +29,9 @@ public:
|
||||
virtual bool isGwNotVsx() = 0;
|
||||
virtual bool isVersionAboveR8110() = 0;
|
||||
virtual bool isReverseProxy() = 0;
|
||||
virtual bool isCloudStorageEnabled() = 0;
|
||||
virtual Maybe<std::tuple<std::string, std::string, std::string>> parseNginxMetadata() = 0;
|
||||
virtual Maybe<std::tuple<std::string, std::string, std::string, std::string, std::string>> readCloudMetadata() = 0;
|
||||
virtual std::map<std::string, std::string> getResolvedDetails() = 0;
|
||||
#if defined(gaia) || defined(smb)
|
||||
virtual bool compareCheckpointVersion(int cp_version, std::function<bool(int, int)> compare_operator) const = 0;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
class I_Downloader
|
||||
{
|
||||
public:
|
||||
virtual Maybe<std::string> downloadFileFromFog(
|
||||
virtual Maybe<std::string> downloadFile(
|
||||
const std::string &checksum,
|
||||
Package::ChecksumTypes,
|
||||
const GetResourceFile &resourse_file
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
const std::string &conf_path) const = 0;
|
||||
virtual bool copyFile(const std::string &src_path, const std::string &dst_path) const = 0;
|
||||
virtual bool doesFileExist(const std::string &file_path) const = 0;
|
||||
virtual void getClusterId() const = 0;
|
||||
virtual void setClusterId() const = 0;
|
||||
virtual void fillKeyInJson(
|
||||
const std::string &filename,
|
||||
const std::string &_key,
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
const std::string &service_id
|
||||
) = 0;
|
||||
|
||||
virtual std::map<std::string, PortNumber> getServiceToPortMap() = 0;
|
||||
virtual std::map<std::string, std::vector<PortNumber>> getServiceToPortMap() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~I_ServiceController() {}
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
const std::string &policy_versions
|
||||
) const = 0;
|
||||
virtual Maybe<void> authenticateAgent() = 0;
|
||||
virtual void registerLocalAgentToFog() = 0;
|
||||
virtual Maybe<void> getUpdate(CheckUpdateRequest &request) = 0;
|
||||
virtual Maybe<std::string> downloadAttributeFile(
|
||||
const GetResourceFile &resourse_file,
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "i_environment.h"
|
||||
#include "i_tenant_manager.h"
|
||||
#include "i_package_handler.h"
|
||||
#include "i_proxy_configuration.h"
|
||||
#include "i_env_details.h"
|
||||
#include "component.h"
|
||||
|
||||
@@ -54,7 +55,8 @@ class OrchestrationComp
|
||||
Singleton::Consume<I_UpdateCommunication>,
|
||||
Singleton::Consume<I_Downloader>,
|
||||
Singleton::Consume<I_ManifestController>,
|
||||
Singleton::Consume<I_EnvDetails>
|
||||
Singleton::Consume<I_EnvDetails>,
|
||||
Singleton::Consume<I_ProxyConfiguration>
|
||||
{
|
||||
public:
|
||||
OrchestrationComp();
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
~OrchestrationStatus();
|
||||
|
||||
void init() override;
|
||||
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "i_package_handler.h"
|
||||
#include "i_orchestration_tools.h"
|
||||
#include "i_shell_cmd.h"
|
||||
#include "i_environment.h"
|
||||
#include "component.h"
|
||||
|
||||
class PackageHandler
|
||||
@@ -24,7 +25,8 @@ class PackageHandler
|
||||
public Component,
|
||||
Singleton::Provide<I_PackageHandler>,
|
||||
Singleton::Consume<I_ShellCmd>,
|
||||
Singleton::Consume<I_OrchestrationTools>
|
||||
Singleton::Consume<I_OrchestrationTools>,
|
||||
Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
PackageHandler();
|
||||
|
||||
@@ -36,7 +36,6 @@ public:
|
||||
title,
|
||||
audience_team,
|
||||
obj,
|
||||
false,
|
||||
MessageCategory::GENERIC,
|
||||
std::forward<Args>(args)...
|
||||
)
|
||||
@@ -48,26 +47,6 @@ public:
|
||||
const std::string &title,
|
||||
const ReportIS::AudienceTeam &audience_team,
|
||||
const T &obj,
|
||||
bool is_async_message,
|
||||
Args ...args)
|
||||
:
|
||||
ReportMessaging(
|
||||
title,
|
||||
audience_team,
|
||||
obj,
|
||||
is_async_message,
|
||||
MessageCategory::GENERIC,
|
||||
std::forward<Args>(args)...
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename ...Args, typename T>
|
||||
ReportMessaging(
|
||||
const std::string &title,
|
||||
const ReportIS::AudienceTeam &audience_team,
|
||||
const T &obj,
|
||||
bool is_async_message,
|
||||
const MessageCategory &message_type,
|
||||
Args ...args)
|
||||
:
|
||||
@@ -77,7 +56,6 @@ public:
|
||||
ReportIS::Severity::INFO,
|
||||
ReportIS::Priority::LOW,
|
||||
obj,
|
||||
is_async_message,
|
||||
message_type,
|
||||
std::forward<Args>(args)...
|
||||
)
|
||||
@@ -99,7 +77,6 @@ public:
|
||||
severity,
|
||||
priority,
|
||||
obj,
|
||||
false,
|
||||
MessageCategory::GENERIC,
|
||||
std::forward<Args>(args)...
|
||||
)
|
||||
@@ -114,7 +91,6 @@ public:
|
||||
const ReportIS::Severity &severity,
|
||||
const ReportIS::Priority &priority,
|
||||
const T &obj,
|
||||
bool _is_async_message,
|
||||
const MessageCategory &message_type,
|
||||
Args ...args)
|
||||
:
|
||||
@@ -131,7 +107,6 @@ public:
|
||||
std::chrono::seconds(0),
|
||||
std::forward<Args>(args)...
|
||||
),
|
||||
is_async_message(_is_async_message),
|
||||
message_type_tag(message_type)
|
||||
{
|
||||
report << LogField("eventObject", obj);
|
||||
@@ -141,11 +116,13 @@ public:
|
||||
|
||||
ReportMessaging & operator<<(const LogField &field);
|
||||
|
||||
Maybe<void, HTTPResponse> sendReportSynchronously();
|
||||
|
||||
void setForceBuffering(bool _force_buffering);
|
||||
|
||||
private:
|
||||
Report report;
|
||||
bool is_async_message;
|
||||
bool is_async_message = true;
|
||||
bool force_buffering = false;
|
||||
MessageCategory message_type_tag;
|
||||
};
|
||||
|
||||
@@ -35,8 +35,10 @@ public:
|
||||
bool isOverSSL() const { return over_ssl; }
|
||||
std::string getPort() const { return port; }
|
||||
std::string getQuery() const { return query; }
|
||||
std::string getHost() const;
|
||||
URLProtocol getProtocol() const { return protocol; }
|
||||
std::string toString() const;
|
||||
void setHost(const std::string &new_host);
|
||||
void setQuery(const std::string &new_query);
|
||||
|
||||
private:
|
||||
@@ -47,6 +49,7 @@ private:
|
||||
std::string base_url;
|
||||
std::string port;
|
||||
std::string query;
|
||||
std::string host;
|
||||
URLProtocol protocol;
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ static const string url = "/api/v1/agents/events";
|
||||
ReportMessaging::~ReportMessaging()
|
||||
{
|
||||
if (!Singleton::exists<I_Messaging>()) return;
|
||||
if (!is_async_message) return;
|
||||
|
||||
LogRest log_rest(report);
|
||||
|
||||
@@ -47,6 +48,25 @@ ReportMessaging::operator<<(const LogField &field)
|
||||
return *this;
|
||||
}
|
||||
|
||||
class LogRestWithReply : public LogRest
|
||||
{
|
||||
public:
|
||||
LogRestWithReply(const Report &report) : LogRest(report) {}
|
||||
|
||||
bool loadJson(const string &) const { return true; }
|
||||
};
|
||||
|
||||
Maybe<void, HTTPResponse>
|
||||
ReportMessaging::sendReportSynchronously()
|
||||
{
|
||||
is_async_message = false;
|
||||
|
||||
LogRestWithReply log_rest(report);
|
||||
|
||||
auto messaging = Singleton::Consume<I_Messaging>::by<ReportMessaging>();
|
||||
return messaging->sendSyncMessage(HTTPMethod::POST, url, log_rest, message_type_tag);
|
||||
}
|
||||
|
||||
void
|
||||
ReportMessaging::setForceBuffering(bool _force_buffering)
|
||||
{
|
||||
|
||||
@@ -103,7 +103,48 @@ TEST_F(ReportMessagingTest, title_only)
|
||||
_
|
||||
)
|
||||
).Times(1);
|
||||
ReportMessaging("test", ReportIS::AudienceTeam::AGENT_CORE, 1, true, ReportIS::Tags::ACCESS_CONTROL);
|
||||
ReportMessaging("test", ReportIS::AudienceTeam::AGENT_CORE, 1, ReportIS::Tags::ACCESS_CONTROL);
|
||||
}
|
||||
|
||||
TEST_F(ReportMessagingTest, sync_sending)
|
||||
{
|
||||
EXPECT_CALL(
|
||||
mock_messaging,
|
||||
sendSyncMessage(
|
||||
_,
|
||||
_,
|
||||
"{\n"
|
||||
" \"log\": {\n"
|
||||
" \"eventTime\": \"Best Time ever\",\n"
|
||||
" \"eventName\": \"test\",\n"
|
||||
" \"eventSeverity\": \"Info\",\n"
|
||||
" \"eventPriority\": \"Low\",\n"
|
||||
" \"eventType\": \"Event Driven\",\n"
|
||||
" \"eventLevel\": \"Log\",\n"
|
||||
" \"eventLogLevel\": \"info\",\n"
|
||||
" \"eventAudience\": \"Internal\",\n"
|
||||
" \"eventAudienceTeam\": \"Agent Core\",\n"
|
||||
" \"eventFrequency\": 0,\n"
|
||||
" \"eventTags\": [\n"
|
||||
" \"Access Control\"\n"
|
||||
" ],\n"
|
||||
" \"eventSource\": {\n"
|
||||
" \"eventTraceId\": \"\",\n"
|
||||
" \"eventSpanId\": \"\",\n"
|
||||
" \"issuingEngineVersion\": \"\",\n"
|
||||
" \"serviceName\": \"Unnamed Nano Service\"\n"
|
||||
" },\n"
|
||||
" \"eventData\": {\n"
|
||||
" \"eventObject\": 1\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}",
|
||||
_,
|
||||
_
|
||||
)
|
||||
).WillOnce(Return(HTTPResponse(HTTPStatusCode::HTTP_OK, "response!!")));
|
||||
ReportMessaging report("test", ReportIS::AudienceTeam::AGENT_CORE, 1, ReportIS::Tags::ACCESS_CONTROL);
|
||||
EXPECT_TRUE(report.sendReportSynchronously().ok());
|
||||
}
|
||||
|
||||
TEST_F(ReportMessagingTest, with_buffering)
|
||||
@@ -144,7 +185,7 @@ TEST_F(ReportMessagingTest, with_buffering)
|
||||
true
|
||||
)
|
||||
).Times(1);
|
||||
ReportMessaging report("test", ReportIS::AudienceTeam::AGENT_CORE, 1, true, ReportIS::Tags::ACCESS_CONTROL);
|
||||
ReportMessaging report("test", ReportIS::AudienceTeam::AGENT_CORE, 1, ReportIS::Tags::ACCESS_CONTROL);
|
||||
report.setForceBuffering(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
include_directories(../waap/include)
|
||||
include_directories(../waap/waap_clib)
|
||||
include_directories(../../attachment-intakers/nginx_attachment)
|
||||
|
||||
add_library(http_geo_filter http_geo_filter.cc)
|
||||
|
||||
@@ -4,10 +4,16 @@
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "cidrs_data.h"
|
||||
#include "generic_rulebase/generic_rulebase.h"
|
||||
#include "generic_rulebase/parameters_config.h"
|
||||
#include "generic_rulebase/triggers_config.h"
|
||||
#include "user_identifiers_config.h"
|
||||
#include "debug.h"
|
||||
#include "config.h"
|
||||
#include "rest.h"
|
||||
@@ -21,9 +27,10 @@ USE_DEBUG_FLAG(D_GEO_FILTER);
|
||||
|
||||
static const LogTriggerConf default_triger;
|
||||
|
||||
class HttpGeoFilter::Impl : public Listener<NewHttpTransactionEvent>
|
||||
class HttpGeoFilter::Impl : public Listener<HttpRequestHeaderEvent>
|
||||
{
|
||||
public:
|
||||
|
||||
void
|
||||
init()
|
||||
{
|
||||
@@ -55,32 +62,42 @@ public:
|
||||
}
|
||||
|
||||
EventVerdict
|
||||
respond(const NewHttpTransactionEvent &event) override
|
||||
respond(const HttpRequestHeaderEvent &event) override
|
||||
{
|
||||
dbgTrace(D_GEO_FILTER) << getListenerName() << " new transaction event";
|
||||
|
||||
if (!ParameterException::isGeoLocationExceptionExists() &&
|
||||
!getConfiguration<GeoConfig>("rulebase", "httpGeoFilter").ok()
|
||||
) {
|
||||
dbgTrace(D_GEO_FILTER) << "No geo location practice nor exception was found. Returning default verdict";
|
||||
if (!event.isLastHeader()) return EventVerdict(ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT);
|
||||
std::set<std::string> xff_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(), ',');
|
||||
}
|
||||
dbgDebug(D_GEO_FILTER) << getListenerName() << " last header, start lookup";
|
||||
|
||||
if (xff_set.size() > 0) {
|
||||
removeTrustedIpsFromXff(xff_set);
|
||||
} else {
|
||||
dbgDebug(D_GEO_FILTER) << "xff not found in headers";
|
||||
}
|
||||
|
||||
auto maybe_source_ip = env->get<IPAddr>(HttpTransactionData::client_ip_ctx);
|
||||
if (!maybe_source_ip.ok()) {
|
||||
dbgWarning(D_GEO_FILTER) << "failed to get source ip from env";
|
||||
return EventVerdict(default_action);
|
||||
}
|
||||
|
||||
I_GeoLocation *i_geo_location = Singleton::Consume<I_GeoLocation>::by<HttpGeoFilter>();
|
||||
auto asset_location = i_geo_location->lookupLocation(event.getSourceIP());
|
||||
if (!asset_location.ok()) {
|
||||
dbgTrace(D_GEO_FILTER) << "Lookup location failed, Error: " << asset_location.getErr();
|
||||
return EventVerdict(default_action);
|
||||
}
|
||||
auto source_ip = convertIpAddrToString(maybe_source_ip.unpack());
|
||||
xff_set.insert(source_ip);
|
||||
|
||||
EnumArray<I_GeoLocation::GeoLocationField, std::string> geo_location_data = asset_location.unpack();
|
||||
|
||||
ngx_http_cp_verdict_e exception_verdict = getExceptionVerdict(event, geo_location_data);
|
||||
ngx_http_cp_verdict_e exception_verdict = getExceptionVerdict(xff_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(event, geo_location_data);
|
||||
ngx_http_cp_verdict_e geo_lookup_verdict = getGeoLookupVerdict(xff_set);
|
||||
if (geo_lookup_verdict != ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT) {
|
||||
return EventVerdict(geo_lookup_verdict);
|
||||
}
|
||||
@@ -88,6 +105,73 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<std::string>
|
||||
split(const std::string& s, char delim) {
|
||||
std::set<std::string> elems;
|
||||
std::stringstream ss(s);
|
||||
std::string value;
|
||||
while (std::getline(ss, value, delim)) {
|
||||
elems.insert(trim(value));
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
static inline std::string <rim(std::string &s) {
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
|
||||
[] (char c) { return !std::isspace(c); }));
|
||||
return s;
|
||||
}
|
||||
|
||||
// trim from end
|
||||
static inline std::string &rtrim(std::string &s) {
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||
[] (char c) { return !std::isspace(c); }).base(), s.end());
|
||||
return s;
|
||||
}
|
||||
|
||||
// trim from both ends
|
||||
static inline std::string &trim(std::string &s) {
|
||||
return ltrim(rtrim(s));
|
||||
}
|
||||
|
||||
void
|
||||
removeTrustedIpsFromXff(std::set<std::string> &xff_set)
|
||||
{
|
||||
auto identify_config = getConfiguration<UsersAllIdentifiersConfig>(
|
||||
"rulebase",
|
||||
"usersIdentifiers"
|
||||
);
|
||||
if (!identify_config.ok()) {
|
||||
dbgDebug(D_GEO_FILTER) << "did not find users identifiers definition in policy";
|
||||
} else {
|
||||
auto trusted_ips = (*identify_config).getHeaderValuesFromConfig("x-forwarded-for");
|
||||
for (auto it = xff_set.begin(); it != xff_set.end();) {
|
||||
if (isIpTrusted(*it, trusted_ips)) {
|
||||
dbgTrace(D_GEO_FILTER) << "xff value is in trusted ips: " << *it;
|
||||
it = xff_set.erase(it);
|
||||
} else {
|
||||
dbgTrace(D_GEO_FILTER) << "xff value is not in trusted ips: " << *it;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
isIpTrusted(const string &ip, const vector<string> &trusted_ips)
|
||||
{
|
||||
for (const auto &trusted_ip : trusted_ips) {
|
||||
CIDRSData cidr_data(trusted_ip);
|
||||
if (
|
||||
ip == trusted_ip ||
|
||||
(cidr_data.contains(ip))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string
|
||||
convertIpAddrToString(const IPAddr &ip_to_convert)
|
||||
{
|
||||
@@ -117,54 +201,75 @@ private:
|
||||
}
|
||||
|
||||
ngx_http_cp_verdict_e
|
||||
getGeoLookupVerdict(
|
||||
const NewHttpTransactionEvent &event,
|
||||
const EnumArray<I_GeoLocation::GeoLocationField, std::string> &geo_location_data)
|
||||
getGeoLookupVerdict(const std::set<std::string> &sources)
|
||||
{
|
||||
auto maybe_geo_config = getConfiguration<GeoConfig>("rulebase", "httpGeoFilter");
|
||||
if (!maybe_geo_config.ok()) {
|
||||
dbgWarning(D_GEO_FILTER) << "Failed to load HTTP Geo Filter config. Error:" << maybe_geo_config.getErr();
|
||||
dbgTrace(D_GEO_FILTER) << "Failed to load HTTP Geo Filter config. Error:" << maybe_geo_config.getErr();
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT;
|
||||
}
|
||||
GeoConfig geo_config = maybe_geo_config.unpack();
|
||||
string country_code = geo_location_data[I_GeoLocation::GeoLocationField::COUNTRY_CODE];
|
||||
EnumArray<I_GeoLocation::GeoLocationField, std::string> geo_location_data;
|
||||
I_GeoLocation *i_geo_location = Singleton::Consume<I_GeoLocation>::by<HttpGeoFilter>();
|
||||
|
||||
if (geo_config.isAllowedCountry(country_code)) {
|
||||
dbgTrace(D_GEO_FILTER)
|
||||
<< "geo verdict ACCEPT, practice id: "
|
||||
<< geo_config.getId()
|
||||
<< ", country code: "
|
||||
<< country_code;
|
||||
generateVerdictLog(
|
||||
ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT,
|
||||
event,
|
||||
geo_config.getId(),
|
||||
true,
|
||||
geo_location_data
|
||||
);
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
}
|
||||
if (geo_config.isBlockedCountry(country_code)) {
|
||||
dbgTrace(D_GEO_FILTER)
|
||||
<< "geo verdict DROP, practice id: "
|
||||
<< geo_config.getId()
|
||||
<< ", country code: "
|
||||
<< country_code;
|
||||
generateVerdictLog(
|
||||
ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP,
|
||||
event,
|
||||
geo_config.getId(),
|
||||
true,
|
||||
geo_location_data
|
||||
);
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
|
||||
for (const std::string& source : sources) {
|
||||
Maybe<IPAddr> maybe_source_ip = IPAddr::createIPAddr(source);
|
||||
if (!maybe_source_ip.ok()){
|
||||
dbgWarning(D_GEO_FILTER) <<
|
||||
"create ip address failed for source: " <<
|
||||
source <<
|
||||
", Error: " <<
|
||||
maybe_source_ip.getErr();
|
||||
continue;
|
||||
}
|
||||
auto asset_location = i_geo_location->lookupLocation(maybe_source_ip.unpack());
|
||||
if (!asset_location.ok()) {
|
||||
dbgWarning(D_GEO_FILTER) <<
|
||||
"Lookup location failed for source: " <<
|
||||
source <<
|
||||
", Error: " <<
|
||||
asset_location.getErr();
|
||||
continue;
|
||||
}
|
||||
|
||||
geo_location_data = asset_location.unpack();
|
||||
|
||||
string country_code = geo_location_data[I_GeoLocation::GeoLocationField::COUNTRY_CODE];
|
||||
|
||||
if (geo_config.isAllowedCountry(country_code)) {
|
||||
dbgTrace(D_GEO_FILTER)
|
||||
<< "geo verdict ACCEPT, practice id: "
|
||||
<< geo_config.getId()
|
||||
<< ", country code: "
|
||||
<< country_code;
|
||||
generateVerdictLog(
|
||||
ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT,
|
||||
geo_config.getId(),
|
||||
true,
|
||||
geo_location_data
|
||||
);
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
}
|
||||
if (geo_config.isBlockedCountry(country_code)) {
|
||||
dbgTrace(D_GEO_FILTER)
|
||||
<< "geo verdict DROP, practice id: "
|
||||
<< geo_config.getId()
|
||||
<< ", country code: "
|
||||
<< country_code;
|
||||
generateVerdictLog(
|
||||
ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP,
|
||||
geo_config.getId(),
|
||||
true,
|
||||
geo_location_data
|
||||
);
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
|
||||
}
|
||||
}
|
||||
dbgTrace(D_GEO_FILTER)
|
||||
<< "No matched practice. Returned default action: "
|
||||
<< geo_config.getDefaultAction();
|
||||
generateVerdictLog(
|
||||
convertActionToVerdict(geo_config.getDefaultAction()),
|
||||
event,
|
||||
geo_config.getId(),
|
||||
true,
|
||||
geo_location_data,
|
||||
@@ -176,7 +281,6 @@ private:
|
||||
Maybe<pair<ngx_http_cp_verdict_e, string>>
|
||||
getBehaviorsVerdict(
|
||||
const unordered_map<string, set<string>> &behaviors_map_to_search,
|
||||
const NewHttpTransactionEvent &event,
|
||||
EnumArray<I_GeoLocation::GeoLocationField, std::string> geo_location_data)
|
||||
{
|
||||
bool is_matched = false;
|
||||
@@ -193,7 +297,6 @@ private:
|
||||
dbgTrace(D_GEO_FILTER) << "behavior verdict: DROP, exception id: " << behavior.getId();
|
||||
generateVerdictLog(
|
||||
matched_verdict,
|
||||
event,
|
||||
behavior.getId(),
|
||||
false,
|
||||
geo_location_data
|
||||
@@ -218,63 +321,74 @@ private:
|
||||
}
|
||||
|
||||
ngx_http_cp_verdict_e
|
||||
getExceptionVerdict(
|
||||
const NewHttpTransactionEvent &event,
|
||||
EnumArray<I_GeoLocation::GeoLocationField, std::string> geo_location_data
|
||||
){
|
||||
string country_code = geo_location_data[I_GeoLocation::GeoLocationField::COUNTRY_CODE];
|
||||
string country_name = geo_location_data[I_GeoLocation::GeoLocationField::COUNTRY_NAME];
|
||||
string source_ip = convertIpAddrToString(event.getSourceIP());
|
||||
getExceptionVerdict(const std::set<std::string> &sources) {
|
||||
|
||||
pair<ngx_http_cp_verdict_e, string> curr_matched_behavior;
|
||||
ngx_http_cp_verdict_e verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT;
|
||||
I_GeoLocation *i_geo_location = Singleton::Consume<I_GeoLocation>::by<HttpGeoFilter>();
|
||||
EnumArray<I_GeoLocation::GeoLocationField, std::string> geo_location_data;
|
||||
|
||||
dbgTrace(D_GEO_FILTER)
|
||||
for (const std::string& source : sources) {
|
||||
|
||||
Maybe<IPAddr> maybe_source_ip = IPAddr::createIPAddr(source);
|
||||
if (!maybe_source_ip.ok()){
|
||||
dbgWarning(D_GEO_FILTER) <<
|
||||
"create ip address failed for source: " <<
|
||||
source <<
|
||||
", Error: " <<
|
||||
maybe_source_ip.getErr();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
auto asset_location = i_geo_location->lookupLocation(maybe_source_ip.unpack());
|
||||
if (!asset_location.ok()) {
|
||||
dbgWarning(D_GEO_FILTER) << "Lookup location failed for source: " <<
|
||||
source <<
|
||||
", Error: " <<
|
||||
asset_location.getErr();
|
||||
continue;
|
||||
}
|
||||
geo_location_data = asset_location.unpack();
|
||||
string country_code = geo_location_data[I_GeoLocation::GeoLocationField::COUNTRY_CODE];
|
||||
string country_name = geo_location_data[I_GeoLocation::GeoLocationField::COUNTRY_NAME];
|
||||
dbgTrace(D_GEO_FILTER)
|
||||
<< "Get exception verdict. "
|
||||
<< "country code: "
|
||||
<< country_code
|
||||
<< ", country name: "
|
||||
<< country_name
|
||||
<< ", source ip address: "
|
||||
<< source_ip;
|
||||
<< source;
|
||||
|
||||
unordered_map<string, set<string>> exception_value_source_ip = {{"sourceIP", {source_ip}}};
|
||||
auto matched_behavior_maybe = getBehaviorsVerdict(exception_value_source_ip, event, geo_location_data);
|
||||
if (matched_behavior_maybe.ok()) {
|
||||
curr_matched_behavior = matched_behavior_maybe.unpack();
|
||||
verdict = curr_matched_behavior.first;
|
||||
if (verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP) {
|
||||
return verdict;
|
||||
unordered_map<string, set<string>> exception_value_country_code = {
|
||||
{"countryCode", {country_code}}
|
||||
};
|
||||
auto matched_behavior_maybe = getBehaviorsVerdict(exception_value_country_code, geo_location_data);
|
||||
if (matched_behavior_maybe.ok()) {
|
||||
curr_matched_behavior = matched_behavior_maybe.unpack();
|
||||
verdict = curr_matched_behavior.first;
|
||||
if (verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP) {
|
||||
return verdict;
|
||||
}
|
||||
}
|
||||
|
||||
unordered_map<string, set<string>> exception_value_country_name = {
|
||||
{"countryName", {country_name}}
|
||||
};
|
||||
matched_behavior_maybe = getBehaviorsVerdict(exception_value_country_name, geo_location_data);
|
||||
if (matched_behavior_maybe.ok()) {
|
||||
curr_matched_behavior = matched_behavior_maybe.unpack();
|
||||
verdict = curr_matched_behavior.first;
|
||||
if (verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP) {
|
||||
return verdict;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unordered_map<string, set<string>> exception_value_country_code = {
|
||||
{"countryCode", {country_code}}
|
||||
};
|
||||
matched_behavior_maybe = getBehaviorsVerdict(exception_value_country_code, event, geo_location_data);
|
||||
if (matched_behavior_maybe.ok()) {
|
||||
curr_matched_behavior = matched_behavior_maybe.unpack();
|
||||
verdict = curr_matched_behavior.first;
|
||||
if (verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP) {
|
||||
return verdict;
|
||||
}
|
||||
}
|
||||
|
||||
unordered_map<string, set<string>> exception_value_country_name = {
|
||||
{"countryName", {country_name}}
|
||||
};
|
||||
matched_behavior_maybe = getBehaviorsVerdict(exception_value_country_name, event, geo_location_data);
|
||||
if (matched_behavior_maybe.ok()) {
|
||||
curr_matched_behavior = matched_behavior_maybe.unpack();
|
||||
verdict = curr_matched_behavior.first;
|
||||
if (verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP) {
|
||||
return verdict;
|
||||
}
|
||||
}
|
||||
if (verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT) {
|
||||
generateVerdictLog(
|
||||
verdict,
|
||||
event,
|
||||
curr_matched_behavior.second,
|
||||
false,
|
||||
geo_location_data
|
||||
@@ -286,7 +400,6 @@ private:
|
||||
void
|
||||
generateVerdictLog(
|
||||
const ngx_http_cp_verdict_e &verdict,
|
||||
const NewHttpTransactionEvent &event,
|
||||
const string &matched_id,
|
||||
bool is_geo_filter,
|
||||
const EnumArray<I_GeoLocation::GeoLocationField, std::string> geo_location_data,
|
||||
@@ -307,14 +420,27 @@ private:
|
||||
LogField(matched_on, matched_id),
|
||||
ReportIS::Tags::HTTP_GEO_FILTER
|
||||
);
|
||||
log
|
||||
<< LogField("sourceIP", convertIpAddrToString(event.getSourceIP()))
|
||||
<< LogField("sourcePort", event.getSourcePort())
|
||||
<< LogField("hostName", event.getDestinationHost())
|
||||
<< LogField("httpMethod", event.getHttpMethod())
|
||||
<< LogField("securityAction", is_prevent ? "Prevent" : "Detect");
|
||||
auto env = Singleton::Consume<I_Environment>::by<HttpGeoFilter>();
|
||||
auto source_ip = env->get<IPAddr>(HttpTransactionData::client_ip_ctx);
|
||||
if (source_ip.ok()) log << LogField("sourceIP", convertIpAddrToString(source_ip.unpack()));
|
||||
|
||||
auto source_identifier = env->get<string>(HttpTransactionData::source_identifier);
|
||||
if (source_identifier.ok()) log << LogField("httpSourceId", source_identifier.unpack());
|
||||
|
||||
auto source_port = env->get<string>(HttpTransactionData::client_port_ctx);
|
||||
if (source_port.ok()) log << LogField("sourcePort", source_port.unpack());
|
||||
|
||||
auto host_name = env->get<string>(HttpTransactionData::host_name_ctx);
|
||||
if (host_name.ok()) log << LogField("hostName", host_name.unpack());
|
||||
|
||||
auto method = env->get<string>(HttpTransactionData::method_ctx);
|
||||
if (method.ok()) log << LogField("httpMethod", method.unpack());
|
||||
|
||||
log << LogField("securityAction", is_prevent ? "Prevent" : "Detect");
|
||||
|
||||
if (is_default_action) log << LogField("isDefaultSecurityAction", true);
|
||||
auto xff = env->get<string>(HttpTransactionData::xff_vals_ctx);
|
||||
if (xff.ok()) log << LogField("proxyIP", xff.unpack());
|
||||
|
||||
log
|
||||
<< LogField("sourceCountryCode", geo_location_data[I_GeoLocation::GeoLocationField::COUNTRY_CODE])
|
||||
|
||||
@@ -50,9 +50,13 @@ public:
|
||||
|
||||
private:
|
||||
void readRules(cereal::JSONInputArchive &ar);
|
||||
void readTriggerId(cereal::JSONInputArchive &ar);
|
||||
void readExceptionId(cereal::JSONInputArchive &ar);
|
||||
void readDefaultAction(cereal::JSONInputArchive &ar);
|
||||
|
||||
std::vector<Rule> rules;
|
||||
std::string trigger_id;
|
||||
std::string exception_id;
|
||||
};
|
||||
|
||||
#endif // __IPS_BASIC_POLICY_H__
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "log_generator.h"
|
||||
#include "parsed_context.h"
|
||||
#include "pm_hook.h"
|
||||
#include "i_generic_rulebase.h"
|
||||
|
||||
/// \namespace IPSSignatureSubTypes
|
||||
/// \brief Namespace containing subtypes for IPS signatures.
|
||||
@@ -348,8 +349,16 @@ public:
|
||||
/// \brief Construct a SignatureAndAction object.
|
||||
/// \param _signature The complete signature.
|
||||
/// \param _action The signature action.
|
||||
SignatureAndAction(std::shared_ptr<CompleteSignature> _signature, SignatureAction _action) :
|
||||
signature(_signature), action(_action)
|
||||
SignatureAndAction(
|
||||
std::shared_ptr<CompleteSignature> _signature,
|
||||
SignatureAction _action,
|
||||
std::string _trigger_id,
|
||||
std::string _exception_id)
|
||||
:
|
||||
signature(_signature),
|
||||
action(_action),
|
||||
trigger_id(_trigger_id),
|
||||
exception_id(_exception_id)
|
||||
{}
|
||||
|
||||
/// \brief Check if the signature is matched for prevention.
|
||||
@@ -375,6 +384,11 @@ public:
|
||||
return signature->getContext();
|
||||
}
|
||||
|
||||
LogTriggerConf getTrigger() const;
|
||||
|
||||
std::set<ParameterBehavior>
|
||||
getBehavior(const std::unordered_map<std::string, std::set<std::string>> &exceptions_dict) const;
|
||||
|
||||
private:
|
||||
/// \brief Get the action results for the IPS state.
|
||||
/// \param ips_state The IPS entry.
|
||||
@@ -382,6 +396,8 @@ private:
|
||||
|
||||
std::shared_ptr<CompleteSignature> signature;
|
||||
SignatureAction action;
|
||||
std::string trigger_id;
|
||||
std::string exception_id;
|
||||
};
|
||||
} // namespace IPSSignatureSubTypes
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ public:
|
||||
private:
|
||||
IPSSignatureSubTypes::SignatureAction action = IPSSignatureSubTypes::SignatureAction::IGNORE;
|
||||
std::vector<std::string> file_names;
|
||||
std::string trigger_id;
|
||||
std::string exception_id;
|
||||
};
|
||||
|
||||
#endif // __SNORT_BASIC_POLICY_H__
|
||||
|
||||
@@ -17,6 +17,8 @@ void
|
||||
RuleSelector::load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
readRules(ar);
|
||||
readTriggerId(ar);
|
||||
readExceptionId(ar);
|
||||
readDefaultAction(ar);
|
||||
}
|
||||
|
||||
@@ -36,7 +38,7 @@ RuleSelector::selectSignatures() const
|
||||
if (rule.isSignaturedMatched(*signature)) {
|
||||
if (rule.getAction() != IPSSignatureSubTypes::SignatureAction::IGNORE) {
|
||||
signature->setIndicators("Check Point", signatures_version);
|
||||
res.emplace_back(signature, rule.getAction());
|
||||
res.emplace_back(signature, rule.getAction(), trigger_id, exception_id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -52,6 +54,28 @@ RuleSelector::readRules(cereal::JSONInputArchive &ar)
|
||||
ar(cereal::make_nvp("rules", rules));
|
||||
}
|
||||
|
||||
void
|
||||
RuleSelector::readTriggerId(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
try {
|
||||
ar(cereal::make_nvp("triggers", trigger_id));
|
||||
} catch (const cereal::Exception &e) {
|
||||
ar.setNextName(nullptr);
|
||||
trigger_id = "";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RuleSelector::readExceptionId(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
try {
|
||||
ar(cereal::make_nvp("exceptions", exception_id));
|
||||
} catch (const cereal::Exception &e) {
|
||||
ar.setNextName(nullptr);
|
||||
exception_id = "";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RuleSelector::readDefaultAction(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
|
||||
@@ -280,8 +280,7 @@ SignatureAndAction::getAction(const IPSEntry &ips_state) const
|
||||
exceptions_dict["sourceIdentifier"].insert(*env_source_identifier);
|
||||
}
|
||||
|
||||
I_GenericRulebase *i_rulebase = Singleton::Consume<I_GenericRulebase>::by<IPSComp>();
|
||||
auto behaviors = i_rulebase->getBehavior(exceptions_dict);
|
||||
auto behaviors = getBehavior(exceptions_dict);
|
||||
|
||||
set<BehaviorValue> override_actions;
|
||||
vector<string> override_ids;
|
||||
@@ -315,6 +314,23 @@ static const auto url_query = LogTriggerConf::WebLogFields::webUrlQuery;
|
||||
static const auto res_body = LogTriggerConf::WebLogFields::responseBody;
|
||||
static const auto res_code = LogTriggerConf::WebLogFields::responseCode;
|
||||
|
||||
LogTriggerConf
|
||||
SignatureAndAction::getTrigger() const
|
||||
{
|
||||
if (trigger_id.empty()) return getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log");
|
||||
|
||||
return Singleton::Consume<I_GenericRulebase>::by<IPSComp>()->getLogTriggerConf(trigger_id);
|
||||
}
|
||||
|
||||
set<ParameterBehavior>
|
||||
SignatureAndAction::getBehavior(const unordered_map<string, set<string>> &exceptions_dict) const
|
||||
{
|
||||
I_GenericRulebase *i_rulebase = Singleton::Consume<I_GenericRulebase>::by<IPSComp>();
|
||||
if (exception_id.empty()) return i_rulebase->getBehavior(exceptions_dict);
|
||||
|
||||
return i_rulebase->getParameterException(exception_id).getBehavior(exceptions_dict);
|
||||
}
|
||||
|
||||
bool
|
||||
SignatureAndAction::matchSilent(const Buffer &sample) const
|
||||
{
|
||||
@@ -398,7 +414,7 @@ SignatureAndAction::isMatchedPrevent(const Buffer &context_buffer, const set<PMP
|
||||
|
||||
dbgDebug(D_IPS) << "Signature matched - sending log";
|
||||
|
||||
auto &trigger = getConfigurationWithDefault(default_triger, "rulebase", "log");
|
||||
auto trigger = getTrigger();
|
||||
bool is_prevent = get<0>(override_action) == IPSSignatureSubTypes::SignatureAction::PREVENT;
|
||||
|
||||
auto severity = signature->getSeverity() < IPSLevel::HIGH ? Severity::HIGH : Severity::CRITICAL;
|
||||
|
||||
@@ -596,6 +596,8 @@ TEST_F(ComponentTest, check_filtering_by_year)
|
||||
|
||||
TEST_F(ComponentTest, log_fields)
|
||||
{
|
||||
generic_rulebase.preload();
|
||||
generic_rulebase.init();
|
||||
string config =
|
||||
"{"
|
||||
"\"IPS\": {"
|
||||
@@ -632,6 +634,8 @@ TEST_F(ComponentTest, log_fields)
|
||||
"\"assetId\": \"1-1-1\","
|
||||
"\"practiceId\": \"2-2-2\","
|
||||
"\"practiceName\": \"practice1\","
|
||||
"\"triggers\": \"5eaeefde6765c30010bae8b6\","
|
||||
"\"exceptions\": \"\","
|
||||
"\"defaultAction\": \"Detect\","
|
||||
"\"rules\": ["
|
||||
"{"
|
||||
@@ -643,10 +647,36 @@ TEST_F(ComponentTest, log_fields)
|
||||
"]"
|
||||
"}"
|
||||
"]"
|
||||
"},"
|
||||
"\"rulebase\": {"
|
||||
"\"log\": ["
|
||||
"{"
|
||||
"\"context\": \"triggerId(5eaeefde6765c30010bae8b6)\","
|
||||
"\"triggerName\": \"Logging Trigger\","
|
||||
"\"triggerType\": \"log\","
|
||||
"\"urlForSyslog\": \"\","
|
||||
"\"urlForCef\": \"128.1.1.1:333\","
|
||||
"\"acAllow\": false,"
|
||||
"\"acDrop\": true,"
|
||||
"\"complianceViolations\": true,"
|
||||
"\"complianceWarnings\": true,"
|
||||
"\"logToAgent\": true,"
|
||||
"\"logToCloud\": true,"
|
||||
"\"logToSyslog\": false,"
|
||||
"\"logToCef\": true,"
|
||||
"\"tpDetect\": true,"
|
||||
"\"tpPrevent\": true,"
|
||||
"\"verbosity\": \"Standard\","
|
||||
"\"webBody\": true,"
|
||||
"\"webHeaders\": true,"
|
||||
"\"webRequests\": true,"
|
||||
"\"webUrlPath\": true,"
|
||||
"\"webUrlQuery\": true"
|
||||
"}"
|
||||
"]"
|
||||
"}"
|
||||
"}";
|
||||
loadPolicy(config);
|
||||
setTrigger();
|
||||
|
||||
EXPECT_CALL(table, createStateRValueRemoved(_, _));
|
||||
EXPECT_CALL(table, getState(_)).WillRepeatedly(Return(&entry));
|
||||
@@ -829,6 +859,8 @@ TEST_F(ComponentTest, prxeem_exception_bug)
|
||||
" \"practiceId\": \"2-2-2\","
|
||||
" \"practiceName\": \"practice1\","
|
||||
" \"defaultAction\": \"Prevent\","
|
||||
" \"triggers\": \"\","
|
||||
" \"exceptions\": \"6c3867be-4da5-42c2-93dc-8f509a764004\","
|
||||
" \"rules\": []"
|
||||
" }"
|
||||
" ]"
|
||||
@@ -847,6 +879,11 @@ TEST_F(ComponentTest, prxeem_exception_bug)
|
||||
" \"parameterId\": \"6c3867be-4da5-42c2-93dc-8f509a764003\","
|
||||
" \"parameterType\": \"exceptions\","
|
||||
" \"parameterName\": \"exception\""
|
||||
" },"
|
||||
" {"
|
||||
" \"parameterId\": \"6c3867be-4da5-42c2-93dc-8f509a764004\","
|
||||
" \"parameterType\": \"exceptions\","
|
||||
" \"parameterName\": \"exception\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"zoneId\": \"\","
|
||||
@@ -855,7 +892,7 @@ TEST_F(ComponentTest, prxeem_exception_bug)
|
||||
" ],"
|
||||
" \"exception\": ["
|
||||
" {"
|
||||
" \"context\": \"parameterId(6c3867be-4da5-42c2-93dc-8f509a764003)\","
|
||||
" \"context\": \"parameterId(6c3867be-4da5-42c2-93dc-8f509a764004)\","
|
||||
" \"match\": {"
|
||||
" \"type\": \"operator\","
|
||||
" \"op\": \"and\","
|
||||
|
||||
@@ -16,6 +16,19 @@ using namespace std;
|
||||
void
|
||||
SnortRuleSelector::load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
try {
|
||||
ar(cereal::make_nvp("triggers", trigger_id));
|
||||
} catch (const cereal::Exception &e) {
|
||||
ar.setNextName(nullptr);
|
||||
trigger_id = "";
|
||||
}
|
||||
|
||||
try {
|
||||
ar(cereal::make_nvp("exceptions", exception_id));
|
||||
} catch (const cereal::Exception &e) {
|
||||
ar.setNextName(nullptr);
|
||||
exception_id = "";
|
||||
}
|
||||
string mode;
|
||||
ar(cereal::make_nvp("mode", mode), cereal::make_nvp("files", file_names));
|
||||
|
||||
@@ -38,7 +51,7 @@ SnortRuleSelector::selectSignatures() const
|
||||
|
||||
for (auto &file : file_names) {
|
||||
for (auto &signature : (*signatures).getSignatures(file)) {
|
||||
res.emplace_back(signature, action);
|
||||
res.emplace_back(signature, action, trigger_id, exception_id);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
@@ -142,6 +142,13 @@ string disabled_settings =
|
||||
"}"
|
||||
"],\n";
|
||||
|
||||
|
||||
string local_intelligence =
|
||||
"\"intelligence\":{"
|
||||
" \"local intelligence server ip\":\"127.0.0.1\","
|
||||
" \"local intelligence server primary port\":9090"
|
||||
"}\n,";
|
||||
|
||||
string policy =
|
||||
"\"rulebase\": {"
|
||||
"\"usersIdentifiers\": ["
|
||||
@@ -259,7 +266,7 @@ Layer7AccessControlTest::verifyReport(
|
||||
|
||||
TEST_F(Layer7AccessControlTest, ReturnAcceptVerdict)
|
||||
{
|
||||
stringstream ss_conf(prevent_settings + policy);
|
||||
stringstream ss_conf(prevent_settings + local_intelligence + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string intelligence_response_ok = loadIntelligenceResponse("data/ok_intelligence_response.json");
|
||||
@@ -305,7 +312,7 @@ TEST_F(Layer7AccessControlTest, ReturnAcceptVerdict)
|
||||
|
||||
TEST_F(Layer7AccessControlTest, ReturnDropVerdictOnMaliciousReputation)
|
||||
{
|
||||
stringstream ss_conf(prevent_settings + policy);
|
||||
stringstream ss_conf(prevent_settings + local_intelligence + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string malicious_intelligence_response = loadIntelligenceResponse("data/malicious_intelligence_response.json");
|
||||
@@ -351,7 +358,7 @@ TEST_F(Layer7AccessControlTest, ReturnDropVerdictOnMaliciousReputation)
|
||||
|
||||
TEST_F(Layer7AccessControlTest, ReturnDropVerdictCacheBased)
|
||||
{
|
||||
stringstream ss_conf(prevent_settings + policy);
|
||||
stringstream ss_conf(prevent_settings + local_intelligence + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string malicious_intelligence_response = loadIntelligenceResponse("data/malicious_intelligence_response.json");
|
||||
@@ -403,7 +410,7 @@ TEST_F(Layer7AccessControlTest, ReturnDropVerdictCacheBased)
|
||||
|
||||
TEST_F(Layer7AccessControlTest, AcceptOnDetect)
|
||||
{
|
||||
stringstream ss_conf(detect_settings + policy);
|
||||
stringstream ss_conf(detect_settings + local_intelligence + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string malicious_intelligence_response = loadIntelligenceResponse("data/malicious_intelligence_response.json");
|
||||
@@ -449,7 +456,7 @@ TEST_F(Layer7AccessControlTest, AcceptOnDetect)
|
||||
|
||||
TEST_F(Layer7AccessControlTest, FallbackToSourceIPAndDrop)
|
||||
{
|
||||
stringstream ss_conf(prevent_settings + policy);
|
||||
stringstream ss_conf(prevent_settings + local_intelligence + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string malicious_intelligence_response = loadIntelligenceResponse("data/malicious_intelligence_response.json");
|
||||
|
||||
@@ -228,6 +228,7 @@ AccessControlPracticeSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec practice spec";
|
||||
|
||||
parseAppsecJSONKey<string>("name", practice_name, archive_in);
|
||||
parseAppsecJSONKey<string>("practiceMode", mode, archive_in);
|
||||
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
|
||||
parseMandatoryAppsecJSONKey<AccessControlRateLimit>("rateLimit", rate_limit, archive_in);
|
||||
}
|
||||
@@ -255,4 +256,10 @@ AccessControlPracticeSpec::getName() const
|
||||
{
|
||||
return practice_name;
|
||||
}
|
||||
|
||||
const string &
|
||||
AccessControlPracticeSpec::getMode(const std::string &default_mode) const
|
||||
{
|
||||
return isModeInherited(mode) ? default_mode : mode;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
@@ -181,12 +181,14 @@ public:
|
||||
const AccessControlRateLimit &getRateLimit() const;
|
||||
const std::string & getAppSecClassName() const;
|
||||
const std::string & getName() const;
|
||||
const std::string & getMode(const std::string &default_mode = "inactive") const;
|
||||
void setName(const std::string &_name);
|
||||
|
||||
private:
|
||||
AccessControlRateLimit rate_limit;
|
||||
std::string appsec_class_name;
|
||||
std::string practice_name;
|
||||
std::string mode;
|
||||
};
|
||||
|
||||
#endif // __ACCESS_CONTROL_PRACTICE_H__
|
||||
|
||||
@@ -587,6 +587,7 @@ public:
|
||||
const NewFileSecurity & getFileSecurity() const;
|
||||
const std::string & getAppSecClassName() const;
|
||||
const std::string & getName() const;
|
||||
const std::string & getMode(const std::string &default_mode = "inactive") const;
|
||||
void setName(const std::string &_name);
|
||||
|
||||
private:
|
||||
@@ -598,6 +599,7 @@ private:
|
||||
NewAppSecPracticeAntiBot anti_bot;
|
||||
std::string appsec_class_name;
|
||||
std::string practice_name;
|
||||
std::string mode;
|
||||
};
|
||||
|
||||
#endif // __NEW_PRACTICE_H__
|
||||
|
||||
@@ -27,7 +27,7 @@ NewAppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Access Control Logging";
|
||||
parseAppsecJSONKey<bool>("allowEvents", ac_allow_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("dropEvents", ac_drop_events, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("dropEvents", ac_drop_events, archive_in, true);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -36,8 +36,7 @@ NewAppsecTriggerAdditionalSuspiciousEventsLogging::load(cereal::JSONInputArchive
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging";
|
||||
parseAppsecJSONKey<bool>("enabled", enabled, archive_in, true);
|
||||
parseAppsecJSONKey<bool>("responseBody", response_body, archive_in, false);
|
||||
//the old code didn't parse the responsecode so ask Noam what is the currenct default value for it
|
||||
parseAppsecJSONKey<bool>("responseCode", response_code, archive_in, false);
|
||||
parseAppsecJSONKey<bool>("responseCode", response_code, archive_in, true);
|
||||
parseAppsecJSONKey<string>("minSeverity", minimum_severity, archive_in, "high");
|
||||
if (valid_severities.count(minimum_severity) == 0) {
|
||||
dbgWarning(D_LOCAL_POLICY)
|
||||
@@ -133,7 +132,7 @@ void
|
||||
NewLoggingService::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseAppsecJSONKey<string>("address", address, archive_in);
|
||||
parseAppsecJSONKey<string>("proto", proto, archive_in);
|
||||
parseAppsecJSONKey<string>("proto", proto, archive_in, "tcp");
|
||||
if (valid_protocols.count(proto) == 0) {
|
||||
dbgWarning(D_LOCAL_POLICY) << "AppSec Logging Service - proto invalid: " << proto;
|
||||
throw PolicyGenException("AppSec Logging Service - proto invalid: " + proto);
|
||||
@@ -175,8 +174,12 @@ void
|
||||
NewAppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger LogDestination";
|
||||
// TBD: support "file"
|
||||
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
|
||||
if (getConfigurationFlag("orchestration-mode") != "hybrid_mode") {
|
||||
// TBD: support "file"
|
||||
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
|
||||
} 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);
|
||||
@@ -184,7 +187,7 @@ NewAppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
|
||||
|
||||
NewStdoutLogging stdout_log;
|
||||
parseAppsecJSONKey<NewStdoutLogging>("stdout", stdout_log, archive_in);
|
||||
agent_local = !(stdout_log.getFormat().empty());
|
||||
parseAppsecJSONKey<bool>("logToAgent", agent_local, archive_in, true);
|
||||
beautify_logs = stdout_log.getFormat() == "json-formatted";
|
||||
parseAppsecJSONKey<NewLoggingService>("syslogService", syslog_service, archive_in);
|
||||
parseAppsecJSONKey<NewLoggingService>("cefService", cef_service, archive_in);
|
||||
|
||||
@@ -1025,6 +1025,7 @@ NewAppSecPracticeSpec::load(cereal::JSONInputArchive &archive_in)
|
||||
parseMandatoryAppsecJSONKey<NewAppSecPracticeWebAttacks>("webAttacks", web_attacks, archive_in);
|
||||
parseAppsecJSONKey<NewAppSecPracticeAntiBot>("antiBot", anti_bot, archive_in);
|
||||
parseAppsecJSONKey<string>("name", practice_name, archive_in);
|
||||
parseAppsecJSONKey<string>("practiceMode", mode, archive_in, "inherited");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1080,4 +1081,11 @@ NewAppSecPracticeSpec::getName() const
|
||||
{
|
||||
return practice_name;
|
||||
}
|
||||
|
||||
const string &
|
||||
NewAppSecPracticeSpec::getMode(const string &default_mode) const
|
||||
{
|
||||
return isModeInherited(mode) ? default_mode : mode;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
@@ -147,7 +147,7 @@ string
|
||||
PolicyMakerUtils::dumpPolicyToFile(
|
||||
const PolicyWrapper &policy,
|
||||
const string &policy_path,
|
||||
const string &settings_path)
|
||||
const string &)
|
||||
{
|
||||
clearElementsMaps();
|
||||
|
||||
@@ -170,6 +170,7 @@ PolicyMakerUtils::dumpPolicyToFile(
|
||||
cereal::JSONOutputArchive ar(settings_ss);
|
||||
policy.getSettings().save(ar);
|
||||
}
|
||||
#if 0
|
||||
string settings_str = settings_ss.str();
|
||||
try {
|
||||
ofstream settings_file(settings_path);
|
||||
@@ -179,6 +180,7 @@ PolicyMakerUtils::dumpPolicyToFile(
|
||||
dbgDebug(D_NGINX_POLICY) << "Error while writing settings to " << settings_path << ", Error: " << e.what();
|
||||
}
|
||||
dbgDebug(D_LOCAL_POLICY) << settings_path << " content: " << settings_str;
|
||||
#endif
|
||||
|
||||
return policy_str;
|
||||
}
|
||||
@@ -1002,8 +1004,9 @@ PolicyMakerUtils::createIpsSections(
|
||||
auto apssec_practice = getAppsecPracticeSpec<V1beta2AppsecLinuxPolicy, NewAppSecPracticeSpec>(
|
||||
rule_annotations[AnnotationTypes::PRACTICE],
|
||||
policy);
|
||||
const string &override_mode =
|
||||
apssec_practice.getIntrusionPrevention().getMode(apssec_practice.getMode(default_mode));
|
||||
|
||||
const string &override_mode = apssec_practice.getIntrusionPrevention().getMode(default_mode);
|
||||
if (override_mode == "Inactive" || override_mode == "Disabled") return;
|
||||
|
||||
IpsProtectionsSection ips_section = IpsProtectionsSection(
|
||||
@@ -1076,8 +1079,9 @@ PolicyMakerUtils::createSnortSections(
|
||||
auto apssec_practice = getAppsecPracticeSpec<V1beta2AppsecLinuxPolicy, NewAppSecPracticeSpec>(
|
||||
rule_annotations[AnnotationTypes::PRACTICE],
|
||||
policy);
|
||||
const string &override_mode =
|
||||
apssec_practice.getSnortSignatures().getOverrideMode(apssec_practice.getMode(default_mode));
|
||||
|
||||
const string &override_mode = apssec_practice.getSnortSignatures().getOverrideMode(default_mode);
|
||||
if (override_mode == "Inactive" ||
|
||||
override_mode == "Disabled" ||
|
||||
apssec_practice.getSnortSignatures().getFiles().size() == 0) {
|
||||
@@ -1129,7 +1133,7 @@ PolicyMakerUtils::createFileSecuritySections(
|
||||
asset_id,
|
||||
practice_name,
|
||||
practice_id,
|
||||
default_mode
|
||||
apssec_practice.getMode(default_mode)
|
||||
);
|
||||
|
||||
file_security[asset_name] = file_security_section;
|
||||
@@ -1171,7 +1175,7 @@ PolicyMakerUtils::createRateLimitSection(
|
||||
asset_name,
|
||||
url,
|
||||
uri,
|
||||
access_control_practice.getRateLimit().getMode(default_mode),
|
||||
access_control_practice.getRateLimit().getMode(access_control_practice.getMode(default_mode)),
|
||||
practice_id,
|
||||
rule_annotations[AnnotationTypes::ACCESS_CONTROL_PRACTICE],
|
||||
rules
|
||||
@@ -1191,6 +1195,8 @@ PolicyMakerUtils::createWebAppSection(
|
||||
rule_annotations[AnnotationTypes::PRACTICE],
|
||||
policy
|
||||
);
|
||||
const string &practice_mode = apssec_practice.getMode(default_mode);
|
||||
|
||||
PracticeAdvancedConfig practice_advance_config(
|
||||
apssec_practice.getWebAttacks().getMaxHeaderSizeBytes(),
|
||||
apssec_practice.getWebAttacks().getMaxBodySizeKb(),
|
||||
@@ -1206,8 +1212,8 @@ PolicyMakerUtils::createWebAppSection(
|
||||
practice_id,
|
||||
rule_annotations[AnnotationTypes::PRACTICE],
|
||||
rule_config.getContext(),
|
||||
apssec_practice.getWebAttacks().getMinimumConfidence(default_mode),
|
||||
apssec_practice.getWebAttacks().getMode(default_mode),
|
||||
apssec_practice.getWebAttacks().getMinimumConfidence(practice_mode),
|
||||
apssec_practice.getWebAttacks().getMode(practice_mode),
|
||||
practice_advance_config,
|
||||
apssec_practice.getAntiBot(),
|
||||
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]],
|
||||
|
||||
@@ -387,8 +387,12 @@ void
|
||||
AppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger LogDestination";
|
||||
// TBD: support "file"
|
||||
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
|
||||
if (getConfigurationFlag("orchestration-mode") != "hybrid_mode") {
|
||||
// TBD: support "file"
|
||||
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
|
||||
} 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);
|
||||
|
||||
@@ -12,6 +12,8 @@ add_subdirectory(manifest_controller)
|
||||
add_subdirectory(update_communication)
|
||||
add_subdirectory(details_resolver)
|
||||
add_subdirectory(health_check)
|
||||
add_subdirectory(health_check_manager)
|
||||
add_subdirectory(updates_process_reporter)
|
||||
add_subdirectory(env_details)
|
||||
|
||||
#add_subdirectory(orchestration_ut)
|
||||
|
||||
@@ -32,6 +32,7 @@ class DetailsResolver::Impl
|
||||
Singleton::Provide<I_DetailsResolver>::From<DetailsResolver>
|
||||
{
|
||||
public:
|
||||
void init() { handler.init(); }
|
||||
Maybe<string> getHostname() override;
|
||||
Maybe<string> getPlatform() override;
|
||||
Maybe<string> getArch() override;
|
||||
@@ -43,6 +44,8 @@ public:
|
||||
bool isGwNotVsx() override;
|
||||
bool isVersionAboveR8110() override;
|
||||
bool isReverseProxy() override;
|
||||
bool isCloudStorageEnabled() override;
|
||||
Maybe<tuple<string, string, string, string, string>> readCloudMetadata() override;
|
||||
Maybe<tuple<string, string, string>> parseNginxMetadata() override;
|
||||
#if defined(gaia) || defined(smb)
|
||||
bool compareCheckpointVersion(int cp_version, std::function<bool(int, int)> compare_operator) const override;
|
||||
@@ -134,6 +137,18 @@ DetailsResolver::Impl::isReverseProxy()
|
||||
return getenv("DOCKER_RPM_ENABLED") && getenv("DOCKER_RPM_ENABLED") == string("true");
|
||||
}
|
||||
|
||||
bool
|
||||
DetailsResolver::Impl::isCloudStorageEnabled()
|
||||
{
|
||||
auto cloud_storage_mode_override = getProfileAgentSetting<bool>("agent.cloudStorage.enabled");
|
||||
if (cloud_storage_mode_override.ok()) {
|
||||
dbgInfo(D_ORCHESTRATOR) << "Received cloud-storage mode override: " << *cloud_storage_mode_override;
|
||||
return *cloud_storage_mode_override;
|
||||
}
|
||||
|
||||
return getenv("CLOUD_STORAGE_ENABLED") && getenv("CLOUD_STORAGE_ENABLED") == string("true");
|
||||
}
|
||||
|
||||
bool
|
||||
DetailsResolver::Impl::isKernelVersion3OrHigher()
|
||||
{
|
||||
@@ -174,17 +189,16 @@ DetailsResolver::Impl::getCheckpointVersion() const
|
||||
{
|
||||
#ifdef gaia
|
||||
static const string cmd =
|
||||
"echo $CPDIR | awk -F'-' '{print $NF}' | cut -c 2- |"
|
||||
" awk -F'.' '{ if( NF == 1 ) {print $1\"00\"} else {print $1$2} }'";
|
||||
"echo $CPDIR | awk '{sub(/.*-R/,\"\"); sub(/\\/.*/,\"\")}/^[0-9]*$/{$0=$0\".00\"}{sub(/\\./, \"\"); print}'";
|
||||
#else // smb
|
||||
static const string cmd = "sqlcmd 'select major,minor from cpver' |"
|
||||
"awk '{if ($1 == \"major\") v += (substr($3,2) * 100);"
|
||||
" if ($1 == \"minor\") v += $3; } END { print v}'";
|
||||
|
||||
#endif // gaia
|
||||
auto version_out = DetailsResolvingHanlder::getCommandOutput(cmd);
|
||||
int cp_version = 0;
|
||||
if (version_out.ok()) {
|
||||
dbgTrace(D_ORCHESTRATOR) << "Identified version " << version_out.unpack();
|
||||
stringstream version_stream(version_out.unpack());
|
||||
version_stream >> cp_version;
|
||||
}
|
||||
@@ -286,10 +300,77 @@ DetailsResolver::Impl::parseNginxMetadata()
|
||||
return make_tuple(config_opt, cc_opt, nginx_version);
|
||||
}
|
||||
|
||||
Maybe<tuple<string, string, string, string, string>>
|
||||
DetailsResolver::Impl::readCloudMetadata()
|
||||
{
|
||||
auto env_read_cloud_metadata = []() -> Maybe<tuple<string, string, string, string, string>> {
|
||||
string account_id = getenv("CLOUD_ACCOUNT_ID") ? getenv("CLOUD_ACCOUNT_ID") : "";
|
||||
string vpc_id = getenv("CLOUD_VPC_ID") ? getenv("CLOUD_VPC_ID") : "";
|
||||
string instance_id = getenv("CLOUD_INSTANCE_ID") ? getenv("CLOUD_INSTANCE_ID") : "";
|
||||
string instance_local_ip = getenv("CLOUD_INSTANCE_LOCAL_IP") ? getenv("CLOUD_INSTANCE_LOCAL_IP") : "";
|
||||
string region = getenv("CLOUD_REGION") ? getenv("CLOUD_REGION") : "";
|
||||
|
||||
if (
|
||||
account_id.empty() ||
|
||||
vpc_id.empty() ||
|
||||
instance_id.empty() ||
|
||||
instance_local_ip.empty() ||
|
||||
region.empty()) {
|
||||
return genError("Could not read cloud metadata");
|
||||
}
|
||||
|
||||
return make_tuple(account_id, vpc_id, instance_id, instance_local_ip, region);
|
||||
};
|
||||
|
||||
auto cloud_metadata = env_read_cloud_metadata();
|
||||
if (!cloud_metadata.ok()) {
|
||||
const string cmd = getFilesystemPathConfig() + "/scripts/get-cloud-metadata.sh";
|
||||
dbgTrace(D_ORCHESTRATOR) << cloud_metadata.getErr() << ", trying to fetch it via cmd: " << cmd;
|
||||
|
||||
auto result = DetailsResolvingHanlder::getCommandOutput(cmd);
|
||||
if (result.ok()) {
|
||||
istringstream iss(result.unpack());
|
||||
string line;
|
||||
while (getline(iss, line)) {
|
||||
size_t pos = line.find('=');
|
||||
if (pos != string::npos) {
|
||||
string key = line.substr(0, pos);
|
||||
string value = line.substr(pos + 1);
|
||||
if (!key.empty() && !value.empty()) setenv(key.c_str(), value.c_str(), 1);
|
||||
}
|
||||
}
|
||||
cloud_metadata = env_read_cloud_metadata();
|
||||
} else {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Could not fetch cloud metadata from cmd: " << result.getErr();
|
||||
}
|
||||
}
|
||||
|
||||
if (!cloud_metadata.ok()) {
|
||||
dbgWarning(D_ORCHESTRATOR) << cloud_metadata.getErr();
|
||||
return genError("Failed to fetch cloud metadata");
|
||||
}
|
||||
|
||||
dbgTrace(D_ORCHESTRATOR)
|
||||
<< "Successfully fetched cloud metadata: "
|
||||
<< ::get<0>(cloud_metadata.unpack()) << ", "
|
||||
<< ::get<1>(cloud_metadata.unpack()) << ", "
|
||||
<< ::get<2>(cloud_metadata.unpack()) << ", "
|
||||
<< ::get<3>(cloud_metadata.unpack()) << ", "
|
||||
<< ::get<4>(cloud_metadata.unpack());
|
||||
|
||||
return cloud_metadata;
|
||||
}
|
||||
|
||||
DetailsResolver::DetailsResolver() : Component("DetailsResolver"), pimpl(make_unique<Impl>()) {}
|
||||
|
||||
DetailsResolver::~DetailsResolver() {}
|
||||
|
||||
void
|
||||
DetailsResolver::init()
|
||||
{
|
||||
pimpl->init();
|
||||
}
|
||||
|
||||
void
|
||||
DetailsResolver::preload()
|
||||
{
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#define __CHECKPOINT_PRODUCT_HANDLERS_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#if defined(gaia)
|
||||
|
||||
@@ -32,6 +34,17 @@ checkSAMLSupportedBlade(const string &command_output)
|
||||
return genError("Current host does not have SAML capability");
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
checkIDABlade(const string &command_output)
|
||||
{
|
||||
string idaBlade = "identityServer";
|
||||
if (command_output.find(idaBlade) != string::npos) {
|
||||
return string("true");
|
||||
}
|
||||
|
||||
return genError("Current host does not have IDA installed");
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
checkSAMLPortal(const string &command_output)
|
||||
{
|
||||
@@ -43,9 +56,22 @@ checkSAMLPortal(const string &command_output)
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
getIDASSamlGaia(const string &command_output)
|
||||
checkPepIdaIdnStatus(const string &command_output)
|
||||
{
|
||||
return string("idaSaml_gaia");
|
||||
if (command_output.find("nac_pep_scaled_sharing_enabled = 1") != string::npos) {
|
||||
return string("true");
|
||||
}
|
||||
return genError("Current host does not have PEP control scaled_sharing enabled");
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
getIDAGaiaPackages(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;
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
@@ -76,6 +102,18 @@ checkIsInstallHorizonTelemetrySucceeded(const string &command_output)
|
||||
return command_output;
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
getQUID(const string &command_output)
|
||||
{
|
||||
if (command_output == "" ) return string("false");
|
||||
// validate valid QUID - contains exactly 4 '-'
|
||||
if (std::count(command_output.begin(), command_output.end(), '-') != 4) {
|
||||
return genError("not valid QUID");
|
||||
}
|
||||
return command_output;
|
||||
}
|
||||
|
||||
|
||||
Maybe<string>
|
||||
checkHasSDWan(const string &command_output)
|
||||
{
|
||||
@@ -92,6 +130,26 @@ checkCanUpdateSDWanData(const string &command_output)
|
||||
return string("true");
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
checkLsmProfileName(const string &command_output)
|
||||
{
|
||||
if (!command_output.empty()) {
|
||||
return command_output;
|
||||
}
|
||||
|
||||
return genError("LSM profile name was not found");
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
checkLsmProfileUuid(const string &command_output)
|
||||
{
|
||||
if (!command_output.empty()) {
|
||||
return command_output;
|
||||
}
|
||||
|
||||
return genError("LSM profile uuid was not found");
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
getMgmtObjType(const string &command_output)
|
||||
{
|
||||
@@ -271,6 +329,34 @@ getSmbGWIPSecVPNBlade(const string &command_output)
|
||||
{
|
||||
return getSmbBlade(command_output, "IPSec VPN Blade was not found");
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
extractManagements(const string &command_output)
|
||||
{
|
||||
size_t start_pos = command_output.find(":masters(");
|
||||
if (start_pos == string::npos) {
|
||||
return genError("Starting pattern \":masters(\" not found.");
|
||||
}
|
||||
size_t end_pos = command_output.find("))):", start_pos);
|
||||
if (end_pos == string::npos) {
|
||||
return genError("Ending pattern \"))):\" not found.");
|
||||
}
|
||||
string input_string = command_output.substr(start_pos, end_pos - start_pos + 3);
|
||||
string json_output = "[";
|
||||
regex pattern("\\(ReferenceObject\\:Uid\\(\"\\{([\\w-]+)\\}\"\\)\\:Name\\(([^\\)]+)\\)\\:Table\\(([^\\)]+)\\)\\)");
|
||||
smatch matches;
|
||||
auto words_begin = sregex_iterator(input_string.begin(), input_string.end(), pattern);
|
||||
auto words_end = sregex_iterator();
|
||||
for (sregex_iterator i = words_begin; i != words_end; ++i) {
|
||||
const smatch& match = *i;
|
||||
string uid = boost::algorithm::to_lower_copy(match[1].str());
|
||||
string name = match[2].str();
|
||||
if (json_output.back() != '[') json_output += ",";
|
||||
json_output += "{\"Uid\":\"" + uid + "\",\"Name\":\"" + name + "\"}";
|
||||
}
|
||||
json_output += "]";
|
||||
return json_output;
|
||||
}
|
||||
#endif // gaia || smb
|
||||
|
||||
#if defined(gaia)
|
||||
|
||||
@@ -43,9 +43,15 @@ SHELL_PRE_CMD("gunzip local.cfg", "gunzip -c $FWDIR/state/local/FW1/local.cfg.gz
|
||||
#if defined(gaia) || defined(smb)
|
||||
SHELL_CMD_HANDLER("cpProductIntegrationMgmtObjectType", "cpprod_util CPPROD_IsMgmtMachine", getMgmtObjType)
|
||||
SHELL_CMD_HANDLER("prerequisitesForHorizonTelemetry",
|
||||
"[ -f /var/log/nano_agent/cp-nano-horizon-telemetry-prerequisites.log ] "
|
||||
"&& head -1 /var/log/nano_agent/cp-nano-horizon-telemetry-prerequisites.log || echo ''",
|
||||
"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 ] "
|
||||
"&& python3 /opt/CPquid/Quid_Api.py -i /opt/CPotelcol/quid_api/get_global_id.json | jq -r .message || 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)
|
||||
SHELL_CMD_HANDLER("hasSDWan", "[ -f $FWDIR/bin/sdwan_steering ] && echo '1' || echo '0'", checkHasSDWan)
|
||||
SHELL_CMD_HANDLER(
|
||||
"canUpdateSDWanData",
|
||||
@@ -56,6 +62,16 @@ SHELL_CMD_HANDLER(
|
||||
"isSdwanRunning",
|
||||
"[ -v $(pidof cp-nano-sdwan) ] && echo 'false' || echo 'true'",
|
||||
checkIfSdwanRunning)
|
||||
SHELL_CMD_HANDLER(
|
||||
"lsmProfileName",
|
||||
"jq -r .lsm_profile_name /tmp/cpsdwan_getdata_orch.json",
|
||||
checkLsmProfileName
|
||||
)
|
||||
SHELL_CMD_HANDLER(
|
||||
"lsmProfileUuid",
|
||||
"jq -r .lsm_profile_uuid /tmp/cpsdwan_getdata_orch.json",
|
||||
checkLsmProfileUuid
|
||||
)
|
||||
SHELL_CMD_HANDLER(
|
||||
"IP Address",
|
||||
"[ $(cpprod_util FWisDAG) -eq 1 ] && echo \"Dynamic Address\" "
|
||||
@@ -84,8 +100,10 @@ SHELL_CMD_HANDLER(
|
||||
|
||||
#if defined(gaia)
|
||||
SHELL_CMD_HANDLER("hasSAMLSupportedBlade", "enabled_blades", checkSAMLSupportedBlade)
|
||||
SHELL_CMD_HANDLER("hasSAMLPortal", "mpclient status saml-vpn", checkSAMLPortal)
|
||||
SHELL_CMD_HANDLER("requiredNanoServices", "ida_saml_gaia", getIDASSamlGaia)
|
||||
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(
|
||||
"cpProductIntegrationMgmtParentObjectName",
|
||||
"cat $FWDIR/database/myself_objects.C "
|
||||
@@ -134,6 +152,12 @@ SHELL_CMD_HANDLER(
|
||||
"| awk -F '[:()]' '/:masters/ {found=1; next} found && /:Name/ {print $3; exit}'",
|
||||
getSMCBasedMgmtName
|
||||
)
|
||||
SHELL_CMD_HANDLER(
|
||||
"managements",
|
||||
"sed -n '/:masters (/,$p' $FWDIR/database/myself_objects.C |"
|
||||
" sed -e ':a' -e 'N' -e '$!ba' -e 's/\\n//g' -e 's/\t//g' -e 's/ //g' | sed 's/))):.*/)))):/'",
|
||||
extractManagements
|
||||
)
|
||||
#endif //gaia
|
||||
|
||||
#if defined(smb)
|
||||
@@ -184,6 +208,13 @@ SHELL_CMD_HANDLER(
|
||||
"| awk -F '[:()]' '/:masters/ {found=1; next} found && /:Name/ {print $3; exit}'",
|
||||
getSMCBasedMgmtName
|
||||
)
|
||||
|
||||
SHELL_CMD_HANDLER(
|
||||
"managements",
|
||||
"sed -n '/:masters (/,$p' /tmp/local.cfg |"
|
||||
" sed -e ':a' -e 'N' -e '$!ba' -e 's/\\n//g' -e 's/\t//g' -e 's/ //g' | sed 's/))):.*/)))):/'",
|
||||
extractManagements
|
||||
)
|
||||
#endif//smb
|
||||
|
||||
SHELL_CMD_OUTPUT("kernel_version", "uname -r")
|
||||
@@ -223,7 +254,7 @@ FILE_CONTENT_HANDLER(
|
||||
FILE_CONTENT_HANDLER("os_release", "/etc/os-release", getOsRelease)
|
||||
#endif // gaia || smb
|
||||
|
||||
FILE_CONTENT_HANDLER("AppSecModelVersion", "/etc/cp/conf/waap/waap.data", getWaapModelVersion)
|
||||
FILE_CONTENT_HANDLER("AppSecModelVersion", "<FILESYSTEM-PREFIX>/conf/waap/waap.data", getWaapModelVersion)
|
||||
|
||||
#endif // FILE_CONTENT_HANDLER
|
||||
|
||||
|
||||
@@ -36,9 +36,12 @@ using FileContentHandler = function<Maybe<string>(shared_ptr<istream> file_otput
|
||||
|
||||
#include "checkpoint_product_handlers.h"
|
||||
|
||||
static const string filesystem_place_holder = "<FILESYSTEM-PREFIX>";
|
||||
|
||||
class DetailsResolvingHanlder::Impl
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
map<string, string> getResolvedDetails() const;
|
||||
static Maybe<string> getCommandOutput(const string &cmd);
|
||||
|
||||
@@ -70,6 +73,28 @@ private:
|
||||
};
|
||||
#undef SHELL_POST_CMD
|
||||
|
||||
void
|
||||
DetailsResolvingHanlder::Impl::init()
|
||||
{
|
||||
string actual_filesystem_prefix = getFilesystemPathConfig();
|
||||
size_t place_holder_size = filesystem_place_holder.size();
|
||||
|
||||
for (auto &file_handler : file_content_handlers) {
|
||||
string &path = file_handler.second.first;
|
||||
if (path.substr(0, place_holder_size) == filesystem_place_holder) {
|
||||
path = actual_filesystem_prefix + path.substr(place_holder_size);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &cmd_handler_pair : shell_command_handlers) {
|
||||
string &cmd_str = cmd_handler_pair.second.first;
|
||||
size_t fs_pos = cmd_str.find(filesystem_place_holder);
|
||||
if (fs_pos != string::npos) {
|
||||
cmd_str.replace(fs_pos, place_holder_size, actual_filesystem_prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map<string, string>
|
||||
DetailsResolvingHanlder::Impl::getResolvedDetails() const
|
||||
{
|
||||
@@ -155,6 +180,12 @@ DetailsResolvingHanlder::Impl::getCommandOutput(const string &cmd)
|
||||
DetailsResolvingHanlder::DetailsResolvingHanlder() : pimpl(make_unique<Impl>()) {}
|
||||
DetailsResolvingHanlder::~DetailsResolvingHanlder() {}
|
||||
|
||||
void
|
||||
DetailsResolvingHanlder::init()
|
||||
{
|
||||
return pimpl->init();
|
||||
}
|
||||
|
||||
map<string, string>
|
||||
DetailsResolvingHanlder::getResolvedDetails() const
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
DetailsResolvingHanlder();
|
||||
~DetailsResolvingHanlder();
|
||||
|
||||
void init();
|
||||
std::map<std::string, std::string> getResolvedDetails() const;
|
||||
|
||||
static Maybe<std::string> getCommandOutput(const std::string &cmd);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ADD_DEFINITIONS(-Wno-deprecated-declarations -Dalpine)
|
||||
|
||||
add_library(orchestration_downloader curl_client.cc downloader.cc http_client.cc https_client.cc)
|
||||
add_library(orchestration_downloader curl_client.cc downloader.cc https_client.cc https_client_helper.cc)
|
||||
|
||||
#add_subdirectory(downloader_ut)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "i_orchestration_tools.h"
|
||||
#include "singleton.h"
|
||||
#include "http_client.h"
|
||||
#include "https_client.h"
|
||||
#include "debug.h"
|
||||
#include "config.h"
|
||||
#include "rest.h"
|
||||
@@ -63,7 +63,7 @@ class Downloader::Impl : Singleton::Provide<I_Downloader>::From<Downloader>
|
||||
public:
|
||||
void init();
|
||||
|
||||
Maybe<string> downloadFileFromFog(
|
||||
Maybe<string> downloadFile(
|
||||
const string &checksum,
|
||||
Package::ChecksumTypes checksum_type,
|
||||
const GetResourceFile &resourse_file
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
string getProfileFromMap(const string &tenant_id) const override;
|
||||
|
||||
private:
|
||||
Maybe<string> downloadFileFromFogByHTTP(
|
||||
Maybe<string> downloadAttributeFile(
|
||||
const GetResourceFile &resourse_file,
|
||||
const string &file_name
|
||||
) const;
|
||||
@@ -121,16 +121,21 @@ Downloader::Impl::init()
|
||||
"Default file download path"
|
||||
);
|
||||
|
||||
auto maybe_vs_id = Singleton::Consume<I_Environment>::by<Downloader>()->get<string>("VS ID");
|
||||
if (maybe_vs_id.ok()) {
|
||||
dir_path = dir_path + "/vs" + maybe_vs_id.unpack();
|
||||
}
|
||||
|
||||
Singleton::Consume<I_OrchestrationTools>::by<Downloader>()->createDirectory(dir_path);
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
Downloader::Impl::downloadFileFromFog(
|
||||
Downloader::Impl::downloadFile(
|
||||
const string &checksum,
|
||||
Package::ChecksumTypes checksum_type,
|
||||
const GetResourceFile &resourse_file) const
|
||||
{
|
||||
auto file_path = downloadFileFromFogByHTTP(resourse_file, resourse_file.getFileName() + ".download");
|
||||
auto file_path = downloadAttributeFile(resourse_file, resourse_file.getFileName() + ".download");
|
||||
|
||||
if (!file_path.ok()) {
|
||||
return file_path;
|
||||
@@ -373,11 +378,11 @@ Downloader::Impl::validateChecksum(
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
Downloader::Impl::downloadFileFromFogByHTTP(const GetResourceFile &resourse_file, const string &file_name) const
|
||||
Downloader::Impl::downloadAttributeFile(const GetResourceFile &resourse_file, const string &file_name) const
|
||||
{
|
||||
string file_path = dir_path + "/" + file_name;
|
||||
|
||||
dbgInfo(D_ORCHESTRATOR) << "Downloading file from fog. File: " << resourse_file.getFileName();
|
||||
dbgInfo(D_ORCHESTRATOR) << "Downloading file. File: " << resourse_file.getFileName();
|
||||
|
||||
I_UpdateCommunication *update_communication = Singleton::Consume<I_UpdateCommunication>::by<Downloader>();
|
||||
auto downloaded_file = update_communication->downloadAttributeFile(resourse_file, file_path);
|
||||
@@ -403,17 +408,14 @@ Downloader::Impl::getFileFromLocal(const string &local_file_path, const string &
|
||||
Maybe<string>
|
||||
Downloader::Impl::getFileFromURL(const URLParser &url, const string &file_path, bool auth_required) const
|
||||
{
|
||||
ofstream outFile(file_path, ofstream::out | ofstream::binary);
|
||||
HTTPClient http_client;
|
||||
dbgInfo(D_ORCHESTRATOR) << "Downloading file. URL: " << url;
|
||||
auto get_file_response = http_client.getFile(url, outFile, auth_required);
|
||||
auto get_file_response = HTTPSClient().getFile(url, file_path, auth_required);
|
||||
if (!get_file_response.ok()) {
|
||||
Maybe<string> error = genError("Failed to download file from " + url.getBaseURL().unpack() +
|
||||
". Error: " + get_file_response.getErr());
|
||||
dbgWarning(D_ORCHESTRATOR) << "Download failed";
|
||||
return error;
|
||||
}
|
||||
outFile.close();
|
||||
dbgInfo(D_ORCHESTRATOR) << "Download completed. URL: " << url;
|
||||
return file_path;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ TEST_F(DownloaderTest, doNothing)
|
||||
{
|
||||
}
|
||||
|
||||
TEST_F(DownloaderTest, downloadFileFromFog)
|
||||
TEST_F(DownloaderTest, downloadFile)
|
||||
{
|
||||
string fog_response = "bla bla";
|
||||
string checksum = "123";
|
||||
@@ -55,7 +55,7 @@ TEST_F(DownloaderTest, downloadFileFromFog)
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, isNonEmptyFile("/tmp/virtualSettings.download")).WillOnce(Return(true));
|
||||
|
||||
Maybe<string> downloaded_file = i_downloader->downloadFileFromFog(
|
||||
Maybe<string> downloaded_file = i_downloader->downloadFile(
|
||||
checksum,
|
||||
Package::ChecksumTypes::SHA256,
|
||||
resourse_file
|
||||
@@ -76,7 +76,7 @@ TEST_F(DownloaderTest, downloadFileFromFogFailure)
|
||||
downloadAttributeFile(resourse_file, "/tmp/settings.download")
|
||||
).WillOnce(Return(fog_response));
|
||||
|
||||
Maybe<string> downloaded_file = i_downloader->downloadFileFromFog(
|
||||
Maybe<string> downloaded_file = i_downloader->downloadFile(
|
||||
checksum,
|
||||
Package::ChecksumTypes::SHA256,
|
||||
resourse_file
|
||||
@@ -241,7 +241,7 @@ TEST_F(DownloaderTest, downloadEmptyFileFromFog)
|
||||
calculateChecksum(Package::ChecksumTypes::SHA256, "/tmp/manifest.download")
|
||||
).WillOnce(Return(checksum));
|
||||
|
||||
Maybe<string> downloaded_file = i_downloader->downloadFileFromFog(
|
||||
Maybe<string> downloaded_file = i_downloader->downloadFile(
|
||||
checksum,
|
||||
Package::ChecksumTypes::SHA256,
|
||||
resourse_file
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
// 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 "http_client.h"
|
||||
|
||||
#include "curl_client.h"
|
||||
#include "downloader.h"
|
||||
#include "debug.h"
|
||||
#include "i_encryptor.h"
|
||||
#include "url_parser.h"
|
||||
#include "config.h"
|
||||
#include "i_environment.h"
|
||||
#include "orchestration_comp.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_ORCHESTRATOR);
|
||||
USE_DEBUG_FLAG(D_HTTP_REQUEST);
|
||||
|
||||
// LCOV_EXCL_START Reason: Depends on real download server.
|
||||
class ClientConnection
|
||||
{
|
||||
public:
|
||||
ClientConnection(
|
||||
const URLParser &_url,
|
||||
const Maybe<string> &_proxy_url,
|
||||
const Maybe<uint16_t> &_proxy_port,
|
||||
const Maybe<string> &_proxy_auth,
|
||||
const string &_token)
|
||||
:
|
||||
url(_url),
|
||||
proxy_url(_proxy_url),
|
||||
proxy_port(_proxy_port),
|
||||
proxy_auth(_proxy_auth),
|
||||
token(_token)
|
||||
{
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
handleConnect()
|
||||
{
|
||||
if (!url.getBaseURL().ok()) {
|
||||
return genError("Failed to handle connection. Error: " + url.getBaseURL().getErr());
|
||||
}
|
||||
string server_name = url.getBaseURL().unpack();
|
||||
string port = url.getPort();
|
||||
string query = url.getQuery();
|
||||
string host = server_name;
|
||||
try {
|
||||
if (stoi(port) != 80) {
|
||||
host = host + ":" + port;
|
||||
}
|
||||
} catch (const exception &err) {
|
||||
return genError("Failed to parse port to a number. Port: " + port );
|
||||
}
|
||||
|
||||
chrono::duration<unsigned int, ratio<1>> sleep_time(60);
|
||||
io_stream.expires_from_now(sleep_time);
|
||||
|
||||
if (proxy_url.ok()) {
|
||||
if (!proxy_port.ok()) {
|
||||
return genError(
|
||||
"Failed to handle connection to server. proxy domain is defined with invalid port, Error: " +
|
||||
proxy_port.getErr()
|
||||
);
|
||||
}
|
||||
io_stream.connect(proxy_url.unpack(), to_string(proxy_port.unpack()));
|
||||
} else {
|
||||
io_stream.connect(server_name, port);
|
||||
}
|
||||
|
||||
if (!io_stream) {
|
||||
return genError("Failed to handle connection to server. Error: " + io_stream.error().message());
|
||||
}
|
||||
|
||||
string request_url = query;
|
||||
if (proxy_url.ok()) {
|
||||
request_url = host + query;
|
||||
}
|
||||
|
||||
stringstream http_request;
|
||||
http_request << "GET http://" << request_url << " HTTP/1.1\r\n";
|
||||
http_request << "Host: " << host << "\r\n";
|
||||
if (!token.empty()) {
|
||||
http_request << "Authorization: " << "Bearer " << token << "\r\n";
|
||||
}
|
||||
http_request << "User-Agent: Infinity Next (a7030abf93a4c13)\r\n";
|
||||
|
||||
auto i_trace_env = Singleton::Consume<I_Environment>::by<OrchestrationComp>();
|
||||
http_request << i_trace_env->getCurrentHeaders();
|
||||
http_request << "Accept: */*\r\n";
|
||||
|
||||
if (proxy_url.ok()) {
|
||||
http_request << "Accept-Encoding: identity";
|
||||
http_request << "Connection: close\r\n";
|
||||
http_request << "Proxy-Connection: Keep-Alive\r\n";
|
||||
|
||||
if (proxy_auth.ok()) {
|
||||
I_Encryptor *encryptor = Singleton::Consume<I_Encryptor>::by<Downloader>();
|
||||
http_request << "Proxy-Authorization: Basic " + encryptor->base64Encode(proxy_auth.unpack()) + "\r\n";
|
||||
}
|
||||
http_request << "\r\n";
|
||||
} else {
|
||||
http_request << "Connection: close\r\n\r\n";
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_REQUEST) << "Sending the following HTTP Request: " << endl << http_request.str();
|
||||
io_stream << http_request.str();
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
handleResponse(ofstream &out_file)
|
||||
{
|
||||
string response_http_version;
|
||||
io_stream >> response_http_version;
|
||||
unsigned int status_code;
|
||||
io_stream >> status_code;
|
||||
string status_message;
|
||||
getline(io_stream, status_message);
|
||||
|
||||
if (!io_stream || response_http_version.substr(0, 5) != "HTTP/") {
|
||||
return genError("Invalid response");
|
||||
}
|
||||
|
||||
if (status_code != 200) {
|
||||
return genError("HTTP response returned with status code " + status_code);
|
||||
}
|
||||
|
||||
string header;
|
||||
vector<string> headers;
|
||||
while (getline(io_stream, header) && header != "\r") {
|
||||
headers.push_back(header);
|
||||
}
|
||||
|
||||
out_file << io_stream.rdbuf();
|
||||
|
||||
dbgTrace(D_HTTP_REQUEST)
|
||||
<< "Received HTTP Response with the following data (downloaded file will not be printed):"
|
||||
<< endl
|
||||
<< response_http_version
|
||||
<< " "
|
||||
<< status_code
|
||||
<< " "
|
||||
<< status_message
|
||||
<< endl
|
||||
<< makeSeparatedStr(headers, "\n");
|
||||
|
||||
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
private:
|
||||
const URLParser url;
|
||||
const Maybe<string> proxy_url;
|
||||
const Maybe<uint16_t> proxy_port;
|
||||
const Maybe<string> proxy_auth;
|
||||
const string &token;
|
||||
boost::asio::ip::tcp::iostream io_stream;
|
||||
};
|
||||
|
||||
Maybe<void>
|
||||
HTTPClient::getFile(const URLParser &url, ofstream &out_file, bool auth_required)
|
||||
{
|
||||
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
|
||||
auto load_env_proxy = proxy_config->loadProxy();
|
||||
if (!load_env_proxy.ok()) return load_env_proxy;
|
||||
|
||||
string token = "";
|
||||
if (auth_required) {
|
||||
token = Singleton::Consume<I_AgentDetails>::by<HTTPClient>()->getAccessToken();
|
||||
}
|
||||
|
||||
if (url.isOverSSL()) {
|
||||
auto get_file_over_ssl_res = getFileSSL(url, out_file, token);
|
||||
if (!get_file_over_ssl_res.ok())
|
||||
{
|
||||
//CURL fallback
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to get file over SSL. Trying via CURL (SSL).";
|
||||
return curlGetFileOverSSL(url, out_file, token);
|
||||
}
|
||||
return get_file_over_ssl_res;
|
||||
}
|
||||
auto get_file_http_res = getFileHttp(url, out_file, token);
|
||||
if (!get_file_http_res.ok())
|
||||
{
|
||||
//CURL fallback
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to get file over HTTP. Trying via CURL (HTTP).";
|
||||
return curlGetFileOverHttp(url, out_file, token);
|
||||
}
|
||||
|
||||
return get_file_http_res;
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
HTTPClient::curlGetFileOverHttp(const URLParser &url, ofstream &out_file, const string &token)
|
||||
{
|
||||
try {
|
||||
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
|
||||
|
||||
HttpCurl http_curl_client(
|
||||
url,
|
||||
out_file,
|
||||
token,
|
||||
proxy_config->getProxyDomain(ProxyProtocol::HTTPS),
|
||||
proxy_config->getProxyPort(ProxyProtocol::HTTPS),
|
||||
proxy_config->getProxyAuthentication(ProxyProtocol::HTTPS));
|
||||
|
||||
http_curl_client.setCurlOpts();
|
||||
bool connection_ok = http_curl_client.connect();
|
||||
if (!connection_ok)
|
||||
{
|
||||
stringstream url_s;
|
||||
url_s << url;
|
||||
string err_msg = string("Failed to get file over HTTP. URL: ") + url_s.str();
|
||||
return genError(err_msg);
|
||||
}
|
||||
|
||||
// As this class is a temporal solution catch all exception types is enabled.
|
||||
} catch (const exception &e) {
|
||||
string err_msg = "Failed to get file over HTTP. Exception: " + string(e.what());
|
||||
return genError(err_msg);
|
||||
}
|
||||
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
HTTPClient::getFileHttp(const URLParser &url, ofstream &out_file, const string &token)
|
||||
{
|
||||
try {
|
||||
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
|
||||
ClientConnection client_connection(
|
||||
url,
|
||||
proxy_config->getProxyDomain(ProxyProtocol::HTTP),
|
||||
proxy_config->getProxyPort(ProxyProtocol::HTTP),
|
||||
proxy_config->getProxyAuthentication(ProxyProtocol::HTTP),
|
||||
token
|
||||
);
|
||||
auto handle_connect_res = client_connection.handleConnect();
|
||||
if (!handle_connect_res.ok()) return handle_connect_res;
|
||||
|
||||
return client_connection.handleResponse(out_file);
|
||||
|
||||
// As this class is a temporal solution catch all exception types is enabled.
|
||||
} catch (const exception &e) {
|
||||
string err_msg = "Failed to get file over HTTP. Exception: " + string(e.what());
|
||||
return genError(err_msg);
|
||||
}
|
||||
|
||||
return Maybe<void>();
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
@@ -1,43 +0,0 @@
|
||||
// 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 __HTTP_CLIENT_H__
|
||||
#define __HTTP_CLIENT_H__
|
||||
|
||||
#include <string>
|
||||
#include "maybe_res.h"
|
||||
#include "url_parser.h"
|
||||
#include "i_agent_details.h"
|
||||
#include "i_proxy_configuration.h"
|
||||
|
||||
// LCOV_EXCL_START Reason: Depends on real download server.
|
||||
class HTTPClient
|
||||
:
|
||||
public Singleton::Consume<I_AgentDetails>,
|
||||
public Singleton::Consume<I_ProxyConfiguration>
|
||||
{
|
||||
public:
|
||||
HTTPClient() = default;
|
||||
|
||||
Maybe<void> getFile(const URLParser &url, std::ofstream &out_file, bool auth_required);
|
||||
|
||||
private:
|
||||
std::string loadCAChainDir();
|
||||
Maybe<void> getFileSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token);
|
||||
Maybe<void> getFileHttp(const URLParser &url, std::ofstream &out_file, const std::string &_token);
|
||||
Maybe<void> curlGetFileOverHttp(const URLParser &url, std::ofstream &out_file, const std::string &_token);
|
||||
Maybe<void> curlGetFileOverSSL(const URLParser &url, std::ofstream &out_file, const std::string &_token);
|
||||
};
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
#endif // __HTTP_CLIENT_H__
|
||||
@@ -11,498 +11,51 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "http_client.h"
|
||||
#include "curl_client.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "i_agent_details.h"
|
||||
#include "i_encryptor.h"
|
||||
#include "downloader.h"
|
||||
#include "config.h"
|
||||
#include "boost/uuid/uuid.hpp"
|
||||
#include "boost/uuid/uuid_generators.hpp"
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include "boost/uuid/uuid_io.hpp"
|
||||
#include "https_client.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <fstream>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind/bind.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <exception>
|
||||
#include <chrono>
|
||||
|
||||
#include "config.h"
|
||||
#include "curl_client.h"
|
||||
|
||||
using namespace boost::placeholders;
|
||||
using boost::asio::ip::tcp;
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_COMMUNICATION);
|
||||
USE_DEBUG_FLAG(D_HTTP_REQUEST);
|
||||
USE_DEBUG_FLAG(D_ORCHESTRATOR);
|
||||
USE_DEBUG_FLAG(D_HTTP_REQUEST);
|
||||
|
||||
// LCOV_EXCL_START Reason: Depends on real download server.
|
||||
class BadResponseFromServer : public exception
|
||||
Maybe<void>
|
||||
HTTPSClient::getFile(const URLParser &url, const string &out_file, bool auth_required)
|
||||
{
|
||||
public:
|
||||
BadResponseFromServer() : message("Bad response returned from server") {}
|
||||
BadResponseFromServer(const string &msg) : message(msg) {}
|
||||
const char *
|
||||
what() const throw()
|
||||
{
|
||||
return message.c_str();
|
||||
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<OrchestrationComp>();
|
||||
auto load_env_proxy = proxy_config->loadProxy();
|
||||
if (!load_env_proxy.ok()) return load_env_proxy;
|
||||
|
||||
string token = "";
|
||||
if (auth_required) {
|
||||
token = Singleton::Consume<I_AgentDetails>::by<OrchestrationComp>()->getAccessToken();
|
||||
}
|
||||
|
||||
private:
|
||||
string message;
|
||||
};
|
||||
if (!url.isOverSSL()) return genError("URL is not over SSL.");
|
||||
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
Client(
|
||||
ofstream &out_file,
|
||||
boost::asio::io_service &io_service,
|
||||
boost::asio::ssl::context &context,
|
||||
const URLParser &_url,
|
||||
const Maybe<string> &_proxy_url,
|
||||
const Maybe<uint16_t> &_proxy_port,
|
||||
const Maybe<string> &_proxy_auth,
|
||||
const string &_token)
|
||||
:
|
||||
out_file(out_file),
|
||||
url(_url),
|
||||
proxy_url(_proxy_url),
|
||||
proxy_port(_proxy_port),
|
||||
proxy_auth(_proxy_auth),
|
||||
resolver_(io_service),
|
||||
deadline(io_service),
|
||||
socket_(io_service),
|
||||
ssl_socket(socket_, context),
|
||||
token(_token)
|
||||
{
|
||||
}
|
||||
if (getFileSSLDirect(url, out_file, token).ok()) return Maybe<void>();
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to get file over SSL directly. Trying indirectly.";
|
||||
|
||||
Maybe<void>
|
||||
handleConnection()
|
||||
{
|
||||
ostream request_stream(&request_);
|
||||
stringstream http_request;
|
||||
http_request << "GET " << url.getQuery() << " HTTP/1.1\r\n";
|
||||
string host = url.getBaseURL().unpack();
|
||||
string port = url.getPort();
|
||||
int port_int;
|
||||
try {
|
||||
port_int = stoi(port);
|
||||
} catch (const exception &err) {
|
||||
dbgWarning(D_COMMUNICATION)
|
||||
<< "Failed to convert port number from string. Port: "
|
||||
<< port
|
||||
<< ", Error: "
|
||||
<< err.what();
|
||||
return genError("Failed to parse port to a number. Port: " + port);
|
||||
}
|
||||
if (port_int != 443) {
|
||||
host = host + ":" + port;
|
||||
}
|
||||
if (getFileSSL(url, out_file, token).ok()) return Maybe<void>();
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to get file over SSL. Trying via CURL (SSL).";
|
||||
|
||||
http_request << "Host: " << host << "\r\n";
|
||||
|
||||
if (!token.empty()) {
|
||||
http_request << "Authorization: " << "Bearer " << token << "\r\n";
|
||||
}
|
||||
http_request << "User-Agent: Infinity Next (a7030abf93a4c13)\r\n";
|
||||
boost::uuids::uuid correlation_id;
|
||||
try {
|
||||
correlation_id = uuid_random_gen();
|
||||
} catch (const boost::uuids::entropy_error &) {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to generate random correlation id - entropy exception";
|
||||
}
|
||||
http_request << "X-Trace-Id: " + boost::uuids::to_string(correlation_id) + "\r\n";
|
||||
http_request << "Accept: */*\r\n";
|
||||
http_request << "Connection: close\r\n\r\n";
|
||||
|
||||
request_stream << http_request.str();
|
||||
|
||||
deadline.expires_from_now(boost::posix_time::minutes(5));
|
||||
deadline.async_wait(boost::bind(&Client::checkDeadline, this, _1));
|
||||
|
||||
if (proxy_url.ok()) {
|
||||
if (!proxy_port.ok()) {
|
||||
dbgWarning(D_COMMUNICATION)
|
||||
<< "Failed to connect to proxy due to invalid port value, Error: "
|
||||
<< proxy_port.getErr();
|
||||
|
||||
return genError(
|
||||
"Failed to handle connection to server. proxy port is invalid, Error: " +
|
||||
proxy_port.getErr()
|
||||
);
|
||||
}
|
||||
if (port_int == 443) host = host + ":" + port;
|
||||
ostream connect_request_stream(&connect_request);
|
||||
stringstream proxy_request;
|
||||
proxy_request << "CONNECT " << host << " HTTP/1.1\r\n";
|
||||
proxy_request << "Host: " << host << "\r\n";
|
||||
if (proxy_auth.ok()) {
|
||||
I_Encryptor *encryptor = Singleton::Consume<I_Encryptor>::by<Downloader>();
|
||||
proxy_request
|
||||
<< "Proxy-Authorization: Basic "
|
||||
<< encryptor->base64Encode(proxy_auth.unpack())
|
||||
<< "\r\n";
|
||||
}
|
||||
proxy_request << "\r\n";
|
||||
|
||||
dbgTrace(D_HTTP_REQUEST) << "Connecting to proxy: " << endl << proxy_request.str();
|
||||
connect_request_stream << proxy_request.str();
|
||||
|
||||
tcp::resolver::query query(proxy_url.unpack(), to_string(proxy_port.unpack()));
|
||||
resolver_.async_resolve(
|
||||
query,
|
||||
boost::bind(
|
||||
&Client::overProxyResolver,
|
||||
this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::iterator
|
||||
)
|
||||
);
|
||||
} else {
|
||||
tcp::resolver::query query(url.getBaseURL().unpack(), port);
|
||||
resolver_.async_resolve(
|
||||
query,
|
||||
boost::bind(
|
||||
&Client::handleResolve,
|
||||
this,
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::iterator
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_REQUEST) << "Sending the following HTTP Request: " << endl << http_request.str();
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
checkDeadline(const boost::system::error_code &err)
|
||||
{
|
||||
if (err) return;
|
||||
if (deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) {
|
||||
boost::system::error_code ignored_ec = boost::asio::error::operation_aborted;
|
||||
socket_.close(ignored_ec);
|
||||
deadline.expires_at(boost::posix_time::pos_infin);
|
||||
return;
|
||||
}
|
||||
deadline.async_wait(boost::bind(&Client::checkDeadline, this, _1));
|
||||
}
|
||||
|
||||
void
|
||||
overProxyResolver(const boost::system::error_code &err, tcp::resolver::iterator endpoint_iterator)
|
||||
{
|
||||
if (!err) {
|
||||
boost::asio::async_connect(socket_, endpoint_iterator,
|
||||
boost::bind(&Client::overProxyHandleConnect, this,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
string err_msg = "Failed to connect to proxy. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
overProxyHandleConnect(const boost::system::error_code &err)
|
||||
{
|
||||
if (!err) {
|
||||
boost::asio::async_write(socket_, connect_request,
|
||||
boost::bind(&Client::overProxyHandleWriteRequest, this,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
string err_msg = "Failed to connect to proxy. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
overProxyHandleWriteRequest(const boost::system::error_code &err)
|
||||
{
|
||||
if (!err) {
|
||||
boost::asio::async_read_until(
|
||||
socket_,
|
||||
response_,
|
||||
"\r\n",
|
||||
boost::bind(&Client::overProxyHandleReadStatusLine, this, boost::asio::placeholders::error)
|
||||
);
|
||||
} else {
|
||||
string err_msg = "Failed to write over proxy. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
overProxyHandleReadStatusLine(const boost::system::error_code &err)
|
||||
{
|
||||
if (err) {
|
||||
string err_msg = "Failed to read status line over proxy. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_msg);
|
||||
}
|
||||
// Check that response is OK.
|
||||
istream response_stream(&response_);
|
||||
string response_http_version;
|
||||
response_stream >> response_http_version;
|
||||
unsigned int status_code;
|
||||
response_stream >> status_code;
|
||||
string status_message;
|
||||
getline(response_stream, status_message);
|
||||
if (!response_stream || response_http_version.substr(0, 5) != "HTTP/") {
|
||||
throw BadResponseFromServer("Invalid response");
|
||||
return;
|
||||
}
|
||||
|
||||
if (status_code != 200) {
|
||||
string err_msg = "Response returned with status code " + status_code;
|
||||
throw BadResponseFromServer(err_msg);
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_REQUEST)
|
||||
<< "Received HTTP Response over proxied connection with the following data:"
|
||||
<< endl
|
||||
<< response_http_version
|
||||
<< " "
|
||||
<< status_code
|
||||
<< " "
|
||||
<< status_message;
|
||||
|
||||
if (getProfileAgentSettingWithDefault<bool>(false, "agent.config.message.ignoreSslValidation") == false) {
|
||||
ssl_socket.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
|
||||
ssl_socket.set_verify_callback(boost::bind(&Client::verifyCertificate, this, _1, _2));
|
||||
} else {
|
||||
dbgWarning(D_HTTP_REQUEST) << "Ignoring SSL validation";
|
||||
}
|
||||
|
||||
ssl_socket.async_handshake(
|
||||
boost::asio::ssl::stream_base::client,
|
||||
boost::bind(&Client::handleHandshake, this, boost::asio::placeholders::error)
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
handleResolve(const boost::system::error_code &err, tcp::resolver::iterator endpoint_iterator)
|
||||
{
|
||||
if (!err) {
|
||||
boost::asio::async_connect(ssl_socket.lowest_layer(), endpoint_iterator,
|
||||
boost::bind(&Client::handleConnect, this,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
string message = "Failed to connect. Error: " + err.message();
|
||||
throw BadResponseFromServer(message);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
verifyCertificate(bool preverified, boost::asio::ssl::verify_context &ctx)
|
||||
{
|
||||
if (!token.empty()) {
|
||||
X509_STORE_CTX *cts = ctx.native_handle();
|
||||
|
||||
switch (X509_STORE_CTX_get_error(cts))
|
||||
{
|
||||
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||
dbgWarning(D_ORCHESTRATOR) << "SSL verification error: X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
|
||||
break;
|
||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
|
||||
dbgWarning(D_ORCHESTRATOR) << "SSL verification error: Certificate not yet valid";
|
||||
break;
|
||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
|
||||
dbgWarning(D_ORCHESTRATOR) << "Certificate expired";
|
||||
break;
|
||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||
dbgDebug(D_ORCHESTRATOR) << "Self signed certificate in chain";
|
||||
if (getConfigurationWithDefault(false, "orchestration", "Self signed certificates acceptable")) {
|
||||
preverified = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!preverified) {
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Certificate verification error number: "
|
||||
<< X509_STORE_CTX_get_error(cts);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return preverified;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
handleConnect(const boost::system::error_code &err)
|
||||
{
|
||||
if (!err) {
|
||||
if (getProfileAgentSettingWithDefault<bool>(false, "agent.config.message.ignoreSslValidation") == false) {
|
||||
ssl_socket.set_verify_mode(
|
||||
boost::asio::ssl::verify_peer |
|
||||
boost::asio::ssl::verify_fail_if_no_peer_cert
|
||||
);
|
||||
ssl_socket.set_verify_callback(boost::bind(&Client::verifyCertificate, this, _1, _2));
|
||||
} else {
|
||||
dbgWarning(D_HTTP_REQUEST) << "Ignoring SSL validation";
|
||||
}
|
||||
|
||||
ssl_socket.async_handshake(boost::asio::ssl::stream_base::client,
|
||||
boost::bind(&Client::handleHandshake, this,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
string err_message = "Failed to connect. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_message);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handleHandshake(const boost::system::error_code &error)
|
||||
{
|
||||
if (!error) {
|
||||
boost::asio::buffer_cast<const char*>(request_.data());
|
||||
|
||||
boost::asio::async_write(ssl_socket, request_,
|
||||
boost::bind(&Client::handleWriteRequest, this,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
string err_message = "Handshake failed. Error: " + error.message();
|
||||
throw BadResponseFromServer(err_message);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handleWriteRequest(const boost::system::error_code &err)
|
||||
{
|
||||
if (!err) {
|
||||
boost::asio::async_read_until(ssl_socket, resp, "\r\n",
|
||||
boost::bind(&Client::handleReadStatusLine, this,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
string err_message = "Failed to handle write request. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_message);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handleReadStatusLine(const boost::system::error_code &err)
|
||||
{
|
||||
if (!err) {
|
||||
istream response_stream(&resp);
|
||||
string http_version;
|
||||
response_stream >> http_version;
|
||||
unsigned int status_code;
|
||||
response_stream >> status_code;
|
||||
string status_message;
|
||||
getline(response_stream, status_message);
|
||||
dbgTrace(D_HTTP_REQUEST)
|
||||
<< "Received HTTP Response with the following data:"
|
||||
<< endl
|
||||
<< http_version
|
||||
<< " "
|
||||
<< status_code;
|
||||
|
||||
if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
|
||||
string err_message = "Invalid response";
|
||||
throw BadResponseFromServer(err_message);
|
||||
}
|
||||
if (status_code != 200) {
|
||||
string err_message = "HTTPS response returned with status code " + to_string(status_code)
|
||||
+ ". URL: " + url.toString();
|
||||
throw BadResponseFromServer(err_message);
|
||||
}
|
||||
|
||||
boost::asio::async_read_until(ssl_socket, resp, "\r\n\r\n",
|
||||
boost::bind(&Client::handleReadHeaders, this,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to read response status. Error:" << err.message();
|
||||
string err_message = "Failed to read status. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_message);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handleReadHeaders(const boost::system::error_code &err)
|
||||
{
|
||||
if (!err) {
|
||||
// Process the response headers.
|
||||
istream response_stream(&resp);
|
||||
string header;
|
||||
vector<string> headers;
|
||||
while (getline(response_stream, header) && header != "\r") {
|
||||
headers.push_back(header);
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_REQUEST) << "Received Response headers:" << endl << makeSeparatedStr(headers, "\n");
|
||||
// Write whatever content we already have to output.
|
||||
if (resp.size() > 0)
|
||||
out_file << &resp;
|
||||
|
||||
// Start reading remaining data until EOF.
|
||||
boost::asio::async_read(ssl_socket, resp,
|
||||
boost::asio::transfer_at_least(1),
|
||||
boost::bind(&Client::handleReadContent, this,
|
||||
boost::asio::placeholders::error));
|
||||
} else {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to read response headers. Error:" << err.message();
|
||||
string err_message = "Failed to read headers. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_message);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handleReadContent(const boost::system::error_code &err)
|
||||
{
|
||||
if (!err) {
|
||||
// Write all of the data that has been read so far.
|
||||
out_file << &resp;
|
||||
// Continue reading remaining data until EOF.
|
||||
boost::asio::async_read(
|
||||
ssl_socket,
|
||||
resp,
|
||||
boost::asio::transfer_at_least(1),
|
||||
boost::bind(&Client::handleReadContent, this, boost::asio::placeholders::error)
|
||||
);
|
||||
} else if (err != boost::asio::error::eof && err != boost::asio::ssl::error::stream_truncated) {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to read response body. Error:" << err.message();
|
||||
string err_message = "Failed to read content. Error: " + err.message();
|
||||
throw BadResponseFromServer(err_message);
|
||||
} else if (err == boost::asio::ssl::error::stream_truncated) {
|
||||
dbgError(D_COMMUNICATION) << "Had SSL warning during reading response body stage. Error:" << err.message();
|
||||
deadline.cancel();
|
||||
} else {
|
||||
deadline.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
ofstream &out_file;
|
||||
const URLParser &url;
|
||||
const Maybe<string> proxy_url;
|
||||
const Maybe<uint16_t> proxy_port;
|
||||
const Maybe<string> proxy_auth;
|
||||
tcp::resolver resolver_;
|
||||
boost::asio::deadline_timer deadline;
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket&> ssl_socket;
|
||||
boost::asio::streambuf request_;
|
||||
boost::asio::streambuf connect_request;
|
||||
boost::asio::streambuf response_;
|
||||
boost::asio::streambuf resp;
|
||||
const string &token;
|
||||
boost::uuids::random_generator uuid_random_gen;
|
||||
};
|
||||
//CURL fallback
|
||||
return curlGetFileOverSSL(url, out_file, token);
|
||||
}
|
||||
|
||||
string
|
||||
HTTPClient::loadCAChainDir()
|
||||
HTTPSClient::loadCAChainDir()
|
||||
{
|
||||
string ca_chain_dir;
|
||||
auto agent_details = Singleton::Consume<I_AgentDetails>::by<Downloader>();
|
||||
auto agent_details = Singleton::Consume<I_AgentDetails>::by<OrchestrationComp>();
|
||||
auto load_ca_chain_dir = agent_details->getOpenSSLDir();
|
||||
if (load_ca_chain_dir.ok()) {
|
||||
ca_chain_dir = load_ca_chain_dir.unpack();
|
||||
@@ -511,69 +64,26 @@ HTTPClient::loadCAChainDir()
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
HTTPClient::getFileSSL(const URLParser &url, ofstream &out_file, const string &token)
|
||||
HTTPSClient::getFileSSL(const URLParser &url, const string &out_file, const string &)
|
||||
{
|
||||
try {
|
||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
||||
if (!token.empty()) {
|
||||
string cert_file_path = getConfigurationWithDefault<string>(
|
||||
getFilesystemPathConfig() + "/certs/fog.pem",
|
||||
"message",
|
||||
"Certificate chain file path"
|
||||
);
|
||||
dbgTrace(D_ORCHESTRATOR) << "Http client, cert file path: " << cert_file_path;
|
||||
auto trusted_ca_directory = getConfiguration<string>("message", "Trusted CA directory");
|
||||
if (trusted_ca_directory.ok() && !trusted_ca_directory.unpack().empty()) {
|
||||
ctx.add_verify_path(trusted_ca_directory.unpack());
|
||||
} else {
|
||||
string cert_file_path = getConfigurationWithDefault<string>(
|
||||
getFilesystemPathConfig() + "/certs/fog.pem",
|
||||
"message",
|
||||
"Certificate chain file path"
|
||||
);
|
||||
ctx.load_verify_file(cert_file_path);
|
||||
}
|
||||
}
|
||||
boost::asio::io_service io_service;
|
||||
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
|
||||
|
||||
Client client(
|
||||
out_file,
|
||||
io_service,
|
||||
ctx,
|
||||
url,
|
||||
proxy_config->getProxyDomain(ProxyProtocol::HTTPS),
|
||||
proxy_config->getProxyPort(ProxyProtocol::HTTPS),
|
||||
proxy_config->getProxyAuthentication(ProxyProtocol::HTTPS),
|
||||
token
|
||||
);
|
||||
|
||||
auto connection_result = client.handleConnection();
|
||||
if (!connection_result.ok()) {
|
||||
return connection_result;
|
||||
};
|
||||
|
||||
auto mainloop = Singleton::Consume<I_MainLoop>::by<Downloader>();
|
||||
while (!io_service.stopped()) {
|
||||
io_service.poll_one();
|
||||
mainloop->yield(true);
|
||||
}
|
||||
} catch (const exception &e) {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to get file over HTTPS. Error:" << string(e.what());
|
||||
string error_str = "Failed to get file over HTTPS, exception: " + string(e.what());
|
||||
return genError(error_str);
|
||||
auto downlaod_file = Singleton::Consume<I_Messaging>::by<OrchestrationComp>()->downloadFile(
|
||||
HTTPMethod::GET,
|
||||
url.getQuery(),
|
||||
out_file
|
||||
);
|
||||
if (!downlaod_file.ok()) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to get file over SSL. Error: " << downlaod_file.getErr().toString();
|
||||
return genError(downlaod_file.getErr().toString());
|
||||
}
|
||||
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
HTTPClient::curlGetFileOverSSL(const URLParser &url, ofstream &out_file, const string &token)
|
||||
HTTPSClient::curlGetFileOverSSL(const URLParser &url, const string &out_file, const string &token)
|
||||
{
|
||||
try {
|
||||
string cert_file_path;
|
||||
if (!token.empty())
|
||||
{
|
||||
if (!token.empty()) {
|
||||
cert_file_path = getConfigurationWithDefault<string>(
|
||||
getFilesystemPathConfig() + "/certs/fog.pem",
|
||||
"message",
|
||||
@@ -581,11 +91,12 @@ HTTPClient::curlGetFileOverSSL(const URLParser &url, ofstream &out_file, const s
|
||||
);
|
||||
}
|
||||
|
||||
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<HTTPClient>();
|
||||
auto proxy_config = Singleton::Consume<I_ProxyConfiguration>::by<OrchestrationComp>();
|
||||
ofstream out_file_stream(out_file, ofstream::out | ofstream::binary);
|
||||
|
||||
HttpsCurl ssl_curl_client(
|
||||
url,
|
||||
out_file,
|
||||
out_file_stream,
|
||||
token,
|
||||
proxy_config->getProxyDomain(ProxyProtocol::HTTPS),
|
||||
proxy_config->getProxyPort(ProxyProtocol::HTTPS),
|
||||
@@ -594,8 +105,7 @@ HTTPClient::curlGetFileOverSSL(const URLParser &url, ofstream &out_file, const s
|
||||
|
||||
ssl_curl_client.setCurlOpts();
|
||||
bool connection_ok = ssl_curl_client.connect();
|
||||
if (!connection_ok)
|
||||
{
|
||||
if (!connection_ok) {
|
||||
stringstream url_s;
|
||||
url_s << url;
|
||||
string err_msg = string("Failed to get file over HTTPS. URL: ") + url_s.str();
|
||||
@@ -603,12 +113,11 @@ HTTPClient::curlGetFileOverSSL(const URLParser &url, ofstream &out_file, const s
|
||||
}
|
||||
|
||||
} catch (const exception &e) {
|
||||
dbgWarning(D_COMMUNICATION) << "Failed to get file over HTTPS. Error:" << string(e.what());
|
||||
dbgWarning(D_HTTP_REQUEST) << "Failed to get file over HTTPS. Error:" << string(e.what());
|
||||
string error_str = "Failed to get file over HTTPS, exception: " + string(e.what());
|
||||
return genError(error_str);
|
||||
}
|
||||
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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 __HTTPS_CLIENT_H__
|
||||
#define __HTTPS_CLIENT_H__
|
||||
|
||||
#include <string>
|
||||
#include "maybe_res.h"
|
||||
#include "url_parser.h"
|
||||
#include "orchestration_comp.h"
|
||||
|
||||
// LCOV_EXCL_START Reason: Depends on real download server.
|
||||
class HTTPSClient
|
||||
{
|
||||
public:
|
||||
Maybe<void> getFile(const URLParser &url, const std::string &out_file, bool auth_required);
|
||||
|
||||
private:
|
||||
std::string loadCAChainDir();
|
||||
Maybe<void> getFileSSL(const URLParser &url, const std::string &out_file, const std::string &_token);
|
||||
Maybe<void> getFileSSLDirect(const URLParser &url, const std::string &out_file, const std::string &_token);
|
||||
Maybe<void> curlGetFileOverSSL(const URLParser &url, const std::string &out_file, const std::string &_token);
|
||||
};
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
#endif // __HTTPS_CLIENT_H__
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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 "https_client.h"
|
||||
|
||||
Maybe<void>
|
||||
HTTPSClient::getFileSSLDirect(const URLParser &, const std::string &, const std::string &)
|
||||
{
|
||||
return genError("No direct downloading in open-source");
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "orchestration_tools.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -22,10 +23,15 @@ USE_DEBUG_FLAG(D_LOCAL_POLICY);
|
||||
|
||||
static const string k8s_service_account = "/var/run/secrets/kubernetes.io/serviceaccount";
|
||||
// LCOV_EXCL_START Reason: can't use on the pipline environment
|
||||
EnvDetails::EnvDetails()
|
||||
EnvDetails::EnvDetails() : env_type(EnvType::LINUX)
|
||||
{
|
||||
auto tools = Singleton::Consume<I_OrchestrationTools>::from<OrchestrationTools>();
|
||||
if (tools->doesFileExist("/.dockerenv")) env_type = EnvType::DOCKER;
|
||||
token = retrieveToken();
|
||||
token.empty() ? env_type = EnvType::LINUX : env_type = EnvType::K8S;
|
||||
if (!token.empty()) {
|
||||
auto env_res = getenv("deployment_type");
|
||||
env_type = env_res != nullptr && env_res == string("non_crd_k8s") ? EnvType::NON_CRD_K8S : EnvType::K8S;
|
||||
}
|
||||
}
|
||||
|
||||
EnvType
|
||||
|
||||
@@ -246,7 +246,7 @@ private:
|
||||
}
|
||||
}
|
||||
routine_id = i_mainloop->addFileRoutine(
|
||||
I_MainLoop::RoutineType::RealTime,
|
||||
I_MainLoop::RoutineType::System,
|
||||
server_sock,
|
||||
[this] () { handleConnection(); },
|
||||
"Health check probe server",
|
||||
@@ -344,7 +344,7 @@ private:
|
||||
dbgDebug(D_HEALTH_CHECK) << "Successfully accepted client, client fd: " << new_client_socket;
|
||||
open_connections_counter++;
|
||||
auto curr_routine = i_mainloop->addOneTimeRoutine(
|
||||
I_MainLoop::RoutineType::RealTime,
|
||||
I_MainLoop::RoutineType::System,
|
||||
[this] ()
|
||||
{
|
||||
auto curr_routine_id = i_mainloop->getCurrentRoutineId().unpack();
|
||||
|
||||
@@ -3,5 +3,5 @@ link_directories(${BOOST_ROOT}/lib)
|
||||
add_unit_test(
|
||||
health_check_ut
|
||||
"health_check_ut.cc"
|
||||
"health_check;messaging;mainloop;singleton;agent_details;config;logging;metric;event_is;health_check_manager;-lboost_regex;-lboost_system"
|
||||
"health_check;updates_process_reporter;messaging;mainloop;singleton;agent_details;config;logging;metric;event_is;health_check_manager;-lboost_regex;-lboost_system"
|
||||
)
|
||||
|
||||
@@ -111,12 +111,12 @@ TEST_F(HealthCheckerTest, clientConnection)
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
|
||||
addFileRoutine(I_MainLoop::RoutineType::System, _, _, _, true)
|
||||
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true)
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, "Health check probe connection handler", true)
|
||||
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
|
||||
|
||||
int socket = 1;
|
||||
@@ -145,7 +145,7 @@ TEST_F(HealthCheckerTest, loadFromDynamicConfiguration)
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
|
||||
addFileRoutine(I_MainLoop::RoutineType::System, _, _, _, true)
|
||||
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
|
||||
|
||||
health_checker.init();
|
||||
@@ -183,7 +183,7 @@ TEST_F(HealthCheckerTest, connectionsLimit)
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
|
||||
addFileRoutine(I_MainLoop::RoutineType::System, _, _, _, true)
|
||||
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
|
||||
|
||||
EXPECT_CALL(mock_mainloop, doesRoutineExist(_)).WillRepeatedly(Return(false));
|
||||
@@ -218,12 +218,12 @@ TEST_F(HealthCheckerTest, disablingAfterEnabled)
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
|
||||
addFileRoutine(I_MainLoop::RoutineType::System, _, _, _, true)
|
||||
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true)
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, "Health check probe connection handler", true)
|
||||
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
|
||||
|
||||
int socket = 1;
|
||||
@@ -273,12 +273,12 @@ TEST_F(HealthCheckerTest, changePortIpConfig)
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
|
||||
addFileRoutine(I_MainLoop::RoutineType::System, _, _, _, true)
|
||||
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true)
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, "Health check probe connection handler", true)
|
||||
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
|
||||
|
||||
int socket = 1;
|
||||
@@ -321,12 +321,12 @@ TEST_F(HealthCheckerTest, FailedHealthCheck)
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addFileRoutine(I_MainLoop::RoutineType::RealTime, _, _, _, true)
|
||||
addFileRoutine(I_MainLoop::RoutineType::System, _, _, _, true)
|
||||
).WillRepeatedly(DoAll(SaveArg<2>(&connection_handler_routine), Return(0)));
|
||||
|
||||
EXPECT_CALL(
|
||||
mock_mainloop,
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::RealTime, _, "Health check probe connection handler", true)
|
||||
addOneTimeRoutine(I_MainLoop::RoutineType::System, _, "Health check probe connection handler", true)
|
||||
).WillOnce(DoAll(SaveArg<1>(&connection_handler_routine), Return(0)));
|
||||
|
||||
int socket = 1;
|
||||
|
||||
@@ -1,3 +1 @@
|
||||
add_library(health_check_manager health_check_manager.cc)
|
||||
|
||||
add_subdirectory(health_check_manager_ut)
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "config.h"
|
||||
#include "cereal/archives/json.hpp"
|
||||
#include "customized_cereal_map.h"
|
||||
#include "updates_process_event.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -79,19 +80,22 @@ class HealthCheckValue
|
||||
public:
|
||||
HealthCheckValue() = default;
|
||||
|
||||
HealthCheckValue(HealthCheckStatus raw_status, const map<string, HealthCheckStatusReply> &descriptions)
|
||||
HealthCheckValue(HealthCheckStatus raw_status, const HealthCheckStatusReply &description)
|
||||
:
|
||||
status(raw_status)
|
||||
{
|
||||
for (const auto &single_stat : descriptions) {
|
||||
if (single_stat.second.getStatus() == HealthCheckStatus::HEALTHY) {
|
||||
dbgTrace(D_HEALTH_CHECK_MANAGER) << "Ignoring healthy status reply. Comp name: " << single_stat.first;
|
||||
continue;
|
||||
}
|
||||
if (description.getStatus() == HealthCheckStatus::HEALTHY) {
|
||||
dbgTrace(D_HEALTH_CHECK_MANAGER)
|
||||
<< "Ignoring healthy status reply. Comp name: "
|
||||
<< description.getCompName();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &status : single_stat.second.getExtendedStatus()) {
|
||||
errors.push_back(HealthCheckError(single_stat.first + " " + status.first, status.second));
|
||||
}
|
||||
for (const auto &extended_status : description.getExtendedStatus()) {
|
||||
errors.push_back(
|
||||
HealthCheckError(description.getCompName() + " " + extended_status.first,
|
||||
extended_status.second
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,9 +117,9 @@ private:
|
||||
class HealthCheckPatch : public ClientRest
|
||||
{
|
||||
public:
|
||||
HealthCheckPatch(HealthCheckStatus raw_status, const map<string, HealthCheckStatusReply> &descriptions)
|
||||
HealthCheckPatch(HealthCheckStatus raw_status, const HealthCheckStatusReply &description)
|
||||
{
|
||||
health_check = HealthCheckValue(raw_status, descriptions);
|
||||
health_check = HealthCheckValue(raw_status, description);
|
||||
}
|
||||
|
||||
C2S_LABEL_PARAM(HealthCheckValue, health_check, "healthCheck");
|
||||
@@ -123,7 +127,8 @@ public:
|
||||
|
||||
class HealthCheckManager::Impl
|
||||
:
|
||||
Singleton::Provide<I_Health_Check_Manager>::From<HealthCheckManager>
|
||||
Singleton::Provide<I_Health_Check_Manager>::From<HealthCheckManager>,
|
||||
public Listener<UpdatesProcessEvent>
|
||||
{
|
||||
public:
|
||||
void
|
||||
@@ -132,6 +137,7 @@ public:
|
||||
auto rest = Singleton::Consume<I_RestApi>::by<HealthCheckManager>();
|
||||
rest->addRestCall<HealthCheckOnDemand>(RestAction::SHOW, "health-check-on-demand");
|
||||
|
||||
registerListener();
|
||||
int interval_in_seconds =
|
||||
getProfileAgentSettingWithDefault<int>(30, "agent.healthCheck.intervalInSeconds");
|
||||
|
||||
@@ -157,9 +163,62 @@ public:
|
||||
void
|
||||
printRepliesHealthStatus(ofstream &oputput_file)
|
||||
{
|
||||
getRegisteredComponentsHealthStatus();
|
||||
cereal::JSONOutputArchive ar(oputput_file);
|
||||
ar(cereal::make_nvp("allComponentsHealthCheckReplies", all_comps_health_status));
|
||||
ar(cereal::make_nvp(health_check_reply.getCompName(), health_check_reply));
|
||||
}
|
||||
|
||||
void
|
||||
upon(const UpdatesProcessEvent &event)
|
||||
{
|
||||
|
||||
OrchestrationStatusFieldType status_field_type = event.getStatusFieldType();
|
||||
HealthCheckStatus _status = convertResultToHealthCheckStatus(event.getResult());
|
||||
string status_field_type_str = convertOrchestrationStatusFieldTypeToStr(status_field_type);
|
||||
|
||||
extended_status[status_field_type_str] =
|
||||
_status == HealthCheckStatus::HEALTHY ?
|
||||
"Success" :
|
||||
event.parseDescription();
|
||||
field_types_status[status_field_type_str] = _status;
|
||||
|
||||
switch(_status) {
|
||||
case HealthCheckStatus::UNHEALTHY: {
|
||||
general_health_aggregated_status = HealthCheckStatus::UNHEALTHY;
|
||||
break;
|
||||
}
|
||||
case HealthCheckStatus::DEGRADED: {
|
||||
for (const auto &type_status : field_types_status) {
|
||||
if ((type_status.first != status_field_type_str)
|
||||
&& (type_status.second == HealthCheckStatus::UNHEALTHY))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
general_health_aggregated_status = HealthCheckStatus::DEGRADED;
|
||||
break;
|
||||
}
|
||||
case HealthCheckStatus::HEALTHY: {
|
||||
for (const auto &type_status : field_types_status) {
|
||||
if ((type_status.first != status_field_type_str)
|
||||
&& (type_status.second == HealthCheckStatus::UNHEALTHY
|
||||
|| type_status.second == HealthCheckStatus::DEGRADED)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
general_health_aggregated_status = HealthCheckStatus::HEALTHY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HealthCheckStatus::IGNORED: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
health_check_reply = HealthCheckStatusReply(
|
||||
"Orchestration",
|
||||
general_health_aggregated_status,
|
||||
extended_status
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -168,9 +227,10 @@ private:
|
||||
{
|
||||
dbgFlow(D_HEALTH_CHECK_MANAGER) << "Sending a health check patch";
|
||||
|
||||
HealthCheckPatch patch_to_send(general_health_aggregated_status, all_comps_health_status);
|
||||
auto messaging = Singleton::Consume<I_Messaging>::by<HealthCheckManager>();
|
||||
return messaging->sendSyncMessageWithoutResponse(
|
||||
HealthCheckPatch patch_to_send(general_health_aggregated_status, health_check_reply);
|
||||
extended_status.clear();
|
||||
field_types_status.clear();
|
||||
return Singleton::Consume<I_Messaging>::by<HealthCheckManager>()->sendSyncMessageWithoutResponse(
|
||||
HTTPMethod::PATCH,
|
||||
"/agents",
|
||||
patch_to_send,
|
||||
@@ -178,59 +238,11 @@ private:
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
getRegisteredComponentsHealthStatus()
|
||||
{
|
||||
vector<HealthCheckStatusReply> health_check_event_reply = HealthCheckStatusEvent().query();
|
||||
all_comps_health_status.clear();
|
||||
for (const auto &reply : health_check_event_reply) {
|
||||
if (reply.getStatus() != HealthCheckStatus::IGNORED) {
|
||||
all_comps_health_status.emplace(reply.getCompName(), reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
calcGeneralHealthAggregatedStatus()
|
||||
{
|
||||
general_health_aggregated_status = HealthCheckStatus::HEALTHY;
|
||||
|
||||
for (const auto &reply : all_comps_health_status) {
|
||||
HealthCheckStatus status = reply.second.getStatus();
|
||||
|
||||
dbgTrace(D_HEALTH_CHECK_MANAGER)
|
||||
<< "Current aggregated status is: "
|
||||
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(
|
||||
general_health_aggregated_status
|
||||
)
|
||||
<< ". Got health status: "
|
||||
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(status)
|
||||
<< "for component: "
|
||||
<< reply.first;
|
||||
|
||||
switch (status) {
|
||||
case HealthCheckStatus::UNHEALTHY : {
|
||||
general_health_aggregated_status = HealthCheckStatus::UNHEALTHY;
|
||||
return;
|
||||
}
|
||||
case HealthCheckStatus::DEGRADED : {
|
||||
general_health_aggregated_status = HealthCheckStatus::DEGRADED;
|
||||
break;
|
||||
}
|
||||
case HealthCheckStatus::IGNORED : break;
|
||||
case HealthCheckStatus::HEALTHY : break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
executeHealthCheck()
|
||||
{
|
||||
dbgFlow(D_HEALTH_CHECK_MANAGER) << "Collecting health status from all registered components.";
|
||||
|
||||
getRegisteredComponentsHealthStatus();
|
||||
calcGeneralHealthAggregatedStatus();
|
||||
|
||||
dbgTrace(D_HEALTH_CHECK_MANAGER)
|
||||
<< "Aggregated status: "
|
||||
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(general_health_aggregated_status);
|
||||
@@ -244,9 +256,43 @@ private:
|
||||
};
|
||||
}
|
||||
|
||||
HealthCheckStatus general_health_aggregated_status;
|
||||
map<string, HealthCheckStatusReply> all_comps_health_status;
|
||||
string
|
||||
convertOrchestrationStatusFieldTypeToStr(OrchestrationStatusFieldType type)
|
||||
{
|
||||
switch (type) {
|
||||
case OrchestrationStatusFieldType::REGISTRATION : return "Registration";
|
||||
case OrchestrationStatusFieldType::MANIFEST : return "Manifest";
|
||||
case OrchestrationStatusFieldType::LAST_UPDATE : return "Last Update";
|
||||
case OrchestrationStatusFieldType::COUNT : return "Count";
|
||||
}
|
||||
|
||||
dbgAssert(false) << "Trying to convert unknown orchestration status field to string.";
|
||||
return "";
|
||||
}
|
||||
|
||||
HealthCheckStatus
|
||||
convertResultToHealthCheckStatus(UpdatesProcessResult result)
|
||||
{
|
||||
switch (result) {
|
||||
case UpdatesProcessResult::SUCCESS : return HealthCheckStatus::HEALTHY;
|
||||
case UpdatesProcessResult::UNSET : return HealthCheckStatus::IGNORED;
|
||||
case UpdatesProcessResult::FAILED : return HealthCheckStatus::UNHEALTHY;
|
||||
case UpdatesProcessResult::DEGRADED : return HealthCheckStatus::DEGRADED;
|
||||
}
|
||||
|
||||
dbgAssert(false) << "Trying to convert unknown update process result field to health check status.";
|
||||
return HealthCheckStatus::IGNORED;
|
||||
}
|
||||
|
||||
HealthCheckStatus general_health_aggregated_status = HealthCheckStatus::HEALTHY;
|
||||
HealthCheckStatusReply health_check_reply = HealthCheckStatusReply(
|
||||
"Orchestration",
|
||||
HealthCheckStatus::HEALTHY,
|
||||
{}
|
||||
);
|
||||
bool should_patch_report;
|
||||
map<string, string> extended_status;
|
||||
map<string, HealthCheckStatus> field_types_status;
|
||||
};
|
||||
|
||||
HealthCheckManager::HealthCheckManager() : Component("HealthCheckManager"), pimpl(make_unique<Impl>()) {}
|
||||
@@ -13,42 +13,13 @@
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_messaging.h"
|
||||
#include "mock/mock_rest_api.h"
|
||||
#include "updates_process_event.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
USE_DEBUG_FLAG(D_HEALTH_CHECK);
|
||||
|
||||
class TestHealthCheckStatusListener : public Listener<HealthCheckStatusEvent>
|
||||
{
|
||||
public:
|
||||
void upon(const HealthCheckStatusEvent &) override {}
|
||||
|
||||
HealthCheckStatusReply
|
||||
respond(const HealthCheckStatusEvent &) override
|
||||
{
|
||||
map<string, string> extended_status;
|
||||
extended_status["team"] = team;
|
||||
extended_status["city"] = city;
|
||||
HealthCheckStatusReply reply(comp_name, status, extended_status);
|
||||
return reply;
|
||||
}
|
||||
|
||||
void setStatus(HealthCheckStatus new_status) { status = new_status; }
|
||||
|
||||
string getListenerName() const { return "TestHealthCheckStatusListener"; }
|
||||
|
||||
private:
|
||||
static const string comp_name;
|
||||
HealthCheckStatus status = HealthCheckStatus::HEALTHY;
|
||||
static const string team;
|
||||
static const string city;
|
||||
};
|
||||
|
||||
const string TestHealthCheckStatusListener::comp_name = "Test";
|
||||
const string TestHealthCheckStatusListener::team = "Hapoel";
|
||||
const string TestHealthCheckStatusListener::city = "Tel-Aviv";
|
||||
|
||||
class TestEnd {};
|
||||
|
||||
class HealthCheckManagerTest : public Test
|
||||
@@ -56,8 +27,7 @@ class HealthCheckManagerTest : public Test
|
||||
public:
|
||||
HealthCheckManagerTest()
|
||||
{
|
||||
Debug::setNewDefaultStdout(&debug_output);
|
||||
Debug::setUnitTestFlag(D_HEALTH_CHECK, Debug::DebugLevel::INFO);
|
||||
Debug::setUnitTestFlag(D_HEALTH_CHECK, Debug::DebugLevel::NOISE);
|
||||
|
||||
EXPECT_CALL(mock_ml, addRecurringRoutine(_, _, _, _, _)).WillRepeatedly(
|
||||
DoAll(SaveArg<2>(&health_check_periodic_routine), Return(1))
|
||||
@@ -70,7 +40,6 @@ public:
|
||||
);
|
||||
|
||||
env.preload();
|
||||
event_listener.registerListener();
|
||||
|
||||
env.init();
|
||||
|
||||
@@ -98,14 +67,12 @@ public:
|
||||
StrictMock<MockMainLoop> mock_ml;
|
||||
StrictMock<MockRestApi> mock_rest;
|
||||
StrictMock<MockMessaging> mock_message;
|
||||
stringstream debug_output;
|
||||
ConfigComponent config;
|
||||
Config::I_Config *i_config = nullptr;
|
||||
::Environment env;
|
||||
HealthCheckManager health_check_manager;
|
||||
I_Health_Check_Manager *i_health_check_manager;
|
||||
unique_ptr<ServerRest> health_check_server;
|
||||
TestHealthCheckStatusListener event_listener;
|
||||
};
|
||||
|
||||
TEST_F(HealthCheckManagerTest, runPeriodicHealthCheckTest)
|
||||
@@ -142,7 +109,20 @@ TEST_F(HealthCheckManagerTest, runPeriodicHealthCheckTest)
|
||||
EXPECT_EQ(actual_body, expected_healthy_body);
|
||||
EXPECT_EQ("Healthy", aggregated_status_str);
|
||||
|
||||
event_listener.setStatus(HealthCheckStatus::DEGRADED);
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::DEGRADED,
|
||||
UpdatesConfigType::SETTINGS,
|
||||
UpdatesFailureReason::DOWNLOAD_FILE,
|
||||
"setting.json",
|
||||
"File not found"
|
||||
).notify();
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::DEGRADED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::DOWNLOAD_FILE,
|
||||
"manifest.json",
|
||||
"File not found"
|
||||
).notify();
|
||||
try {
|
||||
health_check_periodic_routine();
|
||||
} catch (const TestEnd &t) {}
|
||||
@@ -156,16 +136,16 @@ TEST_F(HealthCheckManagerTest, runPeriodicHealthCheckTest)
|
||||
" \"status\": \"Degraded\",\n"
|
||||
" \"errors\": [\n"
|
||||
" {\n"
|
||||
" \"code\": \"Test city\",\n"
|
||||
" \"code\": \"Orchestration Last Update\",\n"
|
||||
" \"message\": [\n"
|
||||
" \"Tel-Aviv\"\n"
|
||||
" \"Failed to download the file setting.json. Error: File not found\"\n"
|
||||
" ],\n"
|
||||
" \"internal\": true\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"code\": \"Test team\",\n"
|
||||
" \"code\": \"Orchestration Manifest\",\n"
|
||||
" \"message\": [\n"
|
||||
" \"Hapoel\"\n"
|
||||
" \"Failed to download the file manifest.json. Error: File not found\"\n"
|
||||
" ],\n"
|
||||
" \"internal\": true\n"
|
||||
" }\n"
|
||||
@@ -196,19 +176,24 @@ TEST_F(HealthCheckManagerTest, runOnDemandHealthCheckTest)
|
||||
config.preload();
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss);
|
||||
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::DOWNLOAD_FILE,
|
||||
"manifest.json",
|
||||
"File not found"
|
||||
).notify();
|
||||
|
||||
stringstream is;
|
||||
is << "{}";
|
||||
health_check_server->performRestCall(is);
|
||||
|
||||
string expected_status =
|
||||
"{\n"
|
||||
" \"allComponentsHealthCheckReplies\": {\n"
|
||||
" \"Test\": {\n"
|
||||
" \"status\": \"Healthy\",\n"
|
||||
" \"extendedStatus\": {\n"
|
||||
" \"city\": \"Tel-Aviv\",\n"
|
||||
" \"team\": \"Hapoel\"\n"
|
||||
" }\n"
|
||||
" \"Orchestration\": {\n"
|
||||
" \"status\": \"Unhealthy\",\n"
|
||||
" \"extendedStatus\": {\n"
|
||||
" \"Manifest\": \"Failed to download the file manifest.json. Error: File not found\"\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}";
|
||||
@@ -47,6 +47,7 @@ HybridModeMetric::upon(const HybridModeMetricEvent &)
|
||||
string cmd_output = maybe_cmd_output.unpack();
|
||||
trim(cmd_output);
|
||||
dbgDebug(D_ORCHESTRATOR) << "Watchdog process counter: " << cmd_output;
|
||||
if (cmd_output.empty()) return;
|
||||
|
||||
try {
|
||||
wd_process_restart.report(stoi(cmd_output));
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "i_rest_api.h"
|
||||
#include "i_time_get.h"
|
||||
#include "i_encryptor.h"
|
||||
#include "i_shell_cmd.h"
|
||||
#include "maybe_res.h"
|
||||
|
||||
class FogAuthenticator
|
||||
@@ -43,10 +44,13 @@ class FogAuthenticator
|
||||
Singleton::Consume<I_DetailsResolver>,
|
||||
Singleton::Consume<I_OrchestrationStatus>,
|
||||
Singleton::Consume<I_OrchestrationTools>,
|
||||
Singleton::Consume<I_EnvDetails>,
|
||||
Singleton::Consume<I_Encryptor>,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_Messaging>,
|
||||
Singleton::Consume<I_TimeGet>
|
||||
Singleton::Consume<I_TimeGet>,
|
||||
Singleton::Consume<I_ShellCmd>,
|
||||
Singleton::Consume<I_Environment>
|
||||
{
|
||||
class AccessToken
|
||||
{
|
||||
@@ -88,6 +92,8 @@ public:
|
||||
void serialize(cereal::JSONOutputArchive &out_ar) const;
|
||||
void serialize(cereal::JSONInputArchive &in_ar);
|
||||
|
||||
std::string getData() const;
|
||||
|
||||
private:
|
||||
AuthenticationType type;
|
||||
std::string data;
|
||||
@@ -103,6 +109,7 @@ public:
|
||||
Maybe<void> authenticateAgent() override;
|
||||
void setAddressExtenesion(const std::string &extension) override;
|
||||
static std::string getUserEdition();
|
||||
void registerLocalAgentToFog() override;
|
||||
|
||||
protected:
|
||||
class UserCredentials
|
||||
@@ -138,6 +145,7 @@ protected:
|
||||
|
||||
bool saveCredentialsToFile(const UserCredentials &credentials) const;
|
||||
Maybe<UserCredentials> getCredentialsFromFile() const;
|
||||
Maybe<RegistrationData> getRegistrationToken();
|
||||
Maybe<RegistrationData> getRegistrationData();
|
||||
|
||||
std::string base64Encode(const std::string &in) const;
|
||||
|
||||
@@ -37,10 +37,7 @@
|
||||
#include "maybe_res.h"
|
||||
#include "declarative_policy_utils.h"
|
||||
|
||||
class HybridCommunication
|
||||
:
|
||||
public FogAuthenticator,
|
||||
Singleton::Consume<I_EnvDetails>
|
||||
class HybridCommunication : public FogAuthenticator
|
||||
{
|
||||
public:
|
||||
void init() override;
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
void init();
|
||||
|
||||
Maybe<void> authenticateAgent() override;
|
||||
void registerLocalAgentToFog() override;
|
||||
Maybe<void> getUpdate(CheckUpdateRequest &request) override;
|
||||
|
||||
Maybe<std::string> downloadAttributeFile(
|
||||
|
||||
@@ -26,6 +26,13 @@ operator<<(std::ostream &os, const Maybe<std::tuple<std::string, std::string, st
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
operator<<(
|
||||
std::ostream &os, const Maybe<std::tuple<std::string, std::string, std::string, std::string, std::string>> &)
|
||||
{
|
||||
return os;
|
||||
}
|
||||
|
||||
class MockDetailsResolver
|
||||
:
|
||||
public Singleton::Provide<I_DetailsResolver>::From<MockProvider<I_DetailsResolver>>
|
||||
@@ -35,12 +42,15 @@ public:
|
||||
MOCK_METHOD0(getPlatform, Maybe<std::string>());
|
||||
MOCK_METHOD0(getArch, Maybe<std::string>());
|
||||
MOCK_METHOD0(getAgentVersion, std::string());
|
||||
MOCK_METHOD0(isCloudStorageEnabled, bool());
|
||||
MOCK_METHOD0(isReverseProxy, bool());
|
||||
MOCK_METHOD0(isKernelVersion3OrHigher, bool());
|
||||
MOCK_METHOD0(isGwNotVsx, bool());
|
||||
MOCK_METHOD0(getResolvedDetails, std::map<std::string, std::string>());
|
||||
MOCK_METHOD0(isVersionAboveR8110, bool());
|
||||
MOCK_METHOD0(parseNginxMetadata, Maybe<std::tuple<std::string, std::string, std::string>>());
|
||||
MOCK_METHOD0(
|
||||
readCloudMetadata, Maybe<std::tuple<std::string, std::string, std::string, std::string, std::string>>());
|
||||
};
|
||||
|
||||
#endif // __MOCK_DETAILS_RESOLVER_H__
|
||||
|
||||
@@ -24,7 +24,7 @@ class MockDownloader :
|
||||
{
|
||||
public:
|
||||
MOCK_CONST_METHOD3(
|
||||
downloadFileFromFog,
|
||||
downloadFile,
|
||||
Maybe<std::string>(const std::string &, Package::ChecksumTypes, const GetResourceFile &)
|
||||
);
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
)
|
||||
);
|
||||
|
||||
typedef std::map<std::string, PortNumber> ServicePortMap;
|
||||
typedef std::map<std::string, std::vector<PortNumber>> ServicePortMap;
|
||||
MOCK_METHOD0(getServiceToPortMap, ServicePortMap());
|
||||
MOCK_METHOD3(updateReconfStatus, void(int id, const std::string &service_name, ReconfStatus status));
|
||||
MOCK_METHOD4(
|
||||
|
||||
@@ -29,6 +29,7 @@ class MockUpdateCommunication :
|
||||
public:
|
||||
void init() {}
|
||||
MOCK_METHOD0(authenticateAgent, Maybe<void>());
|
||||
MOCK_METHOD0(registerLocalAgentToFog, void());
|
||||
MOCK_METHOD1(getUpdate, Maybe<void>(CheckUpdateRequest &));
|
||||
MOCK_METHOD2(
|
||||
downloadAttributeFile,
|
||||
|
||||
@@ -26,7 +26,7 @@ class NamespaceData : public ClientRest
|
||||
{
|
||||
public:
|
||||
bool loadJson(const std::string &json);
|
||||
Maybe<std::string> getNamespaceUidByName(const std::string &name);
|
||||
Maybe<std::string> getNamespaceUidByName(const std::string &name) const;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> ns_name_to_uid;
|
||||
|
||||
@@ -21,8 +21,8 @@ class OrchestrationPolicy
|
||||
{
|
||||
public:
|
||||
const std::string & getFogAddress() const;
|
||||
const unsigned long & getSleepInterval() const;
|
||||
const unsigned long & getErrorSleepInterval() const;
|
||||
unsigned int getSleepInterval() const;
|
||||
unsigned int getErrorSleepInterval() const;
|
||||
|
||||
void serialize(cereal::JSONInputArchive & archive);
|
||||
|
||||
@@ -31,8 +31,8 @@ public:
|
||||
|
||||
private:
|
||||
std::string fog_address;
|
||||
unsigned long sleep_interval;
|
||||
unsigned long error_sleep_interval;
|
||||
unsigned int sleep_interval;
|
||||
unsigned int error_sleep_interval;
|
||||
};
|
||||
|
||||
#endif // __ORCHESTRATION_POLICY_H__
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// 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 __UPDATES_PROCESS_EVENT_H__
|
||||
#define __UPDATES_PROCESS_EVENT_H__
|
||||
|
||||
#include "event.h"
|
||||
#include "singleton.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "i_orchestration_status.h"
|
||||
#include "health_check_status/health_check_status.h"
|
||||
#include "customized_cereal_map.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_UPDATES_PROCESS_REPORTER);
|
||||
|
||||
enum class UpdatesFailureReason {
|
||||
CHECK_UPDATE,
|
||||
REGISTRATION,
|
||||
ORCHESTRATION_SELF_UPDATE,
|
||||
GET_UPDATE_REQUEST,
|
||||
DOWNLOAD_FILE,
|
||||
HANDLE_FILE,
|
||||
INSTALLATION_QUEUE,
|
||||
INSTALL_PACKAGE,
|
||||
CHECKSUM_UNMATCHED,
|
||||
POLICY_CONFIGURATION,
|
||||
POLICY_FOG_CONFIGURATION,
|
||||
NONE
|
||||
|
||||
};
|
||||
|
||||
enum class UpdatesConfigType { MANIFEST, POLICY, SETTINGS, DATA, GENERAL };
|
||||
enum class UpdatesProcessResult { UNSET, SUCCESS, FAILED, DEGRADED };
|
||||
|
||||
static inline std::string
|
||||
convertUpdatesFailureReasonToStr(UpdatesFailureReason reason)
|
||||
{
|
||||
switch (reason) {
|
||||
case UpdatesFailureReason::CHECK_UPDATE : return "CHECK_UPDATE";
|
||||
case UpdatesFailureReason::REGISTRATION : return "REGISTRATION";
|
||||
case UpdatesFailureReason::ORCHESTRATION_SELF_UPDATE : return "ORCHESTRATION_SELF_UPDATE";
|
||||
case UpdatesFailureReason::GET_UPDATE_REQUEST : return "GET_UPDATE_REQUEST";
|
||||
case UpdatesFailureReason::DOWNLOAD_FILE : return "DOWNLOAD_FILE";
|
||||
case UpdatesFailureReason::HANDLE_FILE : return "HANDLE_FILE";
|
||||
case UpdatesFailureReason::INSTALLATION_QUEUE : return "INSTALLATION_QUEUE";
|
||||
case UpdatesFailureReason::INSTALL_PACKAGE : return "INSTALL_PACKAGE";
|
||||
case UpdatesFailureReason::CHECKSUM_UNMATCHED : return "CHECKSUM_UNMATCHED";
|
||||
case UpdatesFailureReason::POLICY_CONFIGURATION : return "POLICY_CONFIGURATION";
|
||||
case UpdatesFailureReason::POLICY_FOG_CONFIGURATION : return "POLICY_FOG_CONFIGURATION";
|
||||
case UpdatesFailureReason::NONE : return "NONE";
|
||||
}
|
||||
|
||||
dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string.";
|
||||
return "";
|
||||
}
|
||||
|
||||
static inline std::string
|
||||
convertUpdatesConfigTypeToStr(UpdatesConfigType type)
|
||||
{
|
||||
switch (type) {
|
||||
case UpdatesConfigType::MANIFEST : return "MANIFEST";
|
||||
case UpdatesConfigType::POLICY : return "POLICY";
|
||||
case UpdatesConfigType::SETTINGS : return "SETTINGS";
|
||||
case UpdatesConfigType::DATA : return "DATA";
|
||||
case UpdatesConfigType::GENERAL : return "GENERAL";
|
||||
}
|
||||
|
||||
dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string.";
|
||||
return "";
|
||||
}
|
||||
|
||||
static inline std::string
|
||||
convertUpdateProcessResultToStr(UpdatesProcessResult result)
|
||||
{
|
||||
switch (result) {
|
||||
case UpdatesProcessResult::SUCCESS : return "SUCCESS";
|
||||
case UpdatesProcessResult::UNSET : return "UNSET";
|
||||
case UpdatesProcessResult::FAILED : return "FAILURE";
|
||||
case UpdatesProcessResult::DEGRADED : return "DEGRADED";
|
||||
}
|
||||
|
||||
dbgWarning(D_UPDATES_PROCESS_REPORTER) << "Trying to convert unknown updates failure reason to string.";
|
||||
return "";
|
||||
}
|
||||
|
||||
class UpdatesProcessEvent : public Event<UpdatesProcessEvent>
|
||||
{
|
||||
public:
|
||||
UpdatesProcessEvent() {}
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult _result,
|
||||
UpdatesConfigType _type,
|
||||
UpdatesFailureReason _reason = UpdatesFailureReason::NONE,
|
||||
const std::string &_detail = "",
|
||||
const std::string &_description = "");
|
||||
|
||||
~UpdatesProcessEvent() {}
|
||||
|
||||
UpdatesProcessResult getResult() const { return result; }
|
||||
UpdatesConfigType getType() const { return type; }
|
||||
UpdatesFailureReason getReason() const { return reason; }
|
||||
std::string getDetail() const { return detail; }
|
||||
std::string getDescription() const { return description; }
|
||||
|
||||
OrchestrationStatusFieldType getStatusFieldType() const;
|
||||
OrchestrationStatusResult getOrchestrationStatusResult() const;
|
||||
|
||||
std::string parseDescription() const;
|
||||
|
||||
private:
|
||||
UpdatesProcessResult result;
|
||||
UpdatesConfigType type;
|
||||
UpdatesFailureReason reason;
|
||||
std::string detail;
|
||||
std::string description;
|
||||
|
||||
};
|
||||
|
||||
#endif // __UPDATES_PROCESS_EVENT_H__
|
||||
@@ -0,0 +1,61 @@
|
||||
// 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 __UPDATES_PROCESS_REPORT_H__
|
||||
#define __UPDATES_PROCESS_REPORT_H__
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "singleton.h"
|
||||
#include "i_time_get.h"
|
||||
#include "updates_process_event.h"
|
||||
|
||||
class UpdatesProcessReport : Singleton::Consume<I_TimeGet>
|
||||
{
|
||||
public:
|
||||
UpdatesProcessReport(
|
||||
UpdatesProcessResult result,
|
||||
UpdatesConfigType type,
|
||||
UpdatesFailureReason reason,
|
||||
const std::string &description)
|
||||
:
|
||||
result(result), type(type), reason(reason), description(description)
|
||||
{
|
||||
time_stamp = Singleton::Consume<I_TimeGet>::by<UpdatesProcessReport>()->getWalltimeStr();
|
||||
}
|
||||
|
||||
std::string
|
||||
toString() const
|
||||
{
|
||||
std::stringstream report;
|
||||
report
|
||||
<< "["
|
||||
<< time_stamp << "] - "
|
||||
<< convertUpdateProcessResultToStr(result) << " | "
|
||||
<< convertUpdatesConfigTypeToStr(type) << " | "
|
||||
<< convertUpdatesFailureReasonToStr(reason) << " | "
|
||||
<< description;
|
||||
|
||||
return report.str();
|
||||
}
|
||||
|
||||
private:
|
||||
UpdatesProcessResult result;
|
||||
UpdatesConfigType type;
|
||||
UpdatesFailureReason reason;
|
||||
std::string description;
|
||||
std::string time_stamp;
|
||||
};
|
||||
|
||||
#endif // __UPDATES_PROCESS_EVENT_H__
|
||||
35
components/generic_rulebase/evaluators/parameter_eval.cc → components/security_apps/orchestration/include/updates_process_reporter.h
Executable file → Normal file
35
components/generic_rulebase/evaluators/parameter_eval.cc → components/security_apps/orchestration/include/updates_process_reporter.h
Executable file → Normal file
@@ -11,28 +11,29 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "generic_rulebase/evaluators/parameter_eval.h"
|
||||
#ifndef __UPDATES_PROCESS_REPORTER_H__
|
||||
#define __UPDATES_PROCESS_REPORTER_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "event.h"
|
||||
#include "singleton.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "i_orchestration_status.h"
|
||||
#include "health_check_status/health_check_status.h"
|
||||
#include "updates_process_event.h"
|
||||
#include "updates_process_report.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string ParameterMatcher::ctx_key = "parameters";
|
||||
|
||||
ParameterMatcher::ParameterMatcher(const vector<string> ¶ms)
|
||||
class UpdatesProcessReporter : public Listener<UpdatesProcessEvent>
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(ParameterMatcher::getName(), params.size(), 1, 1);
|
||||
parameter_id = params[0];
|
||||
}
|
||||
public:
|
||||
void upon(const UpdatesProcessEvent &event) override;
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
ParameterMatcher::evalVariable() const
|
||||
{
|
||||
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
|
||||
return rule.ok() && rule.unpack().isParameterActive(parameter_id);
|
||||
}
|
||||
private:
|
||||
void sendReoprt();
|
||||
|
||||
static std::vector<UpdatesProcessReport> reports;
|
||||
};
|
||||
|
||||
#endif // __UPDATES_PROCESS_REPORTER_H__
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "version.h"
|
||||
#include "log_generator.h"
|
||||
#include "orchestration_comp.h"
|
||||
#include "updates_process_event.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ReportIS;
|
||||
@@ -219,6 +220,13 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file)
|
||||
if (isIgnoreFile(new_manifest_file)) {
|
||||
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new manifest file";
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::HANDLE_FILE,
|
||||
new_manifest_file,
|
||||
"Failed to copy a new manifest file"
|
||||
).notify();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -237,6 +245,13 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file)
|
||||
|
||||
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new manifest file";
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::HANDLE_FILE,
|
||||
new_manifest_file,
|
||||
"Failed to copy a new manifest file"
|
||||
).notify();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -245,6 +260,13 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file)
|
||||
Maybe<map<string, Package>> parsed_manifest = orchestration_tools->loadPackagesFromJson(new_manifest_file);
|
||||
if (!parsed_manifest.ok()) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to parse the new manifest file. File: " << new_manifest_file;
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::HANDLE_FILE,
|
||||
new_manifest_file,
|
||||
"Failed to parse the new manifest file"
|
||||
).notify();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -332,6 +354,13 @@ ManifestController::Impl::updateManifest(const string &new_manifest_file)
|
||||
dbgWarning(D_ORCHESTRATOR)
|
||||
<< "Failed building installation queue. Error: "
|
||||
<< installation_queue_res.getErr();
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::INSTALLATION_QUEUE,
|
||||
"",
|
||||
installation_queue_res.getErr()
|
||||
).notify();
|
||||
return false;
|
||||
}
|
||||
const vector<Package> &installation_queue = installation_queue_res.unpack();
|
||||
@@ -447,11 +476,25 @@ ManifestController::Impl::changeManifestFile(const string &new_manifest_file)
|
||||
dbgDebug(D_ORCHESTRATOR) << "Writing new manifest to file";
|
||||
if (!orchestration_tools->copyFile(new_manifest_file, manifest_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed write new manifest to file";
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::HANDLE_FILE,
|
||||
new_manifest_file,
|
||||
"Failed write new manifest to file"
|
||||
).notify();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!orchestration_tools->isNonEmptyFile(manifest_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to get manifest file data";
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::HANDLE_FILE,
|
||||
manifest_file_path,
|
||||
"Failed to get manifest file data"
|
||||
).notify();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,13 +281,7 @@ TEST_F(ManifestControllerTest, badChecksum)
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist("/etc/cp/packages/my/my")).WillOnce(Return(false));
|
||||
|
||||
string hostname = "hostname";
|
||||
string empty_err;
|
||||
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err));
|
||||
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return( Maybe<string>(hostname)));
|
||||
EXPECT_CALL(
|
||||
mock_status,
|
||||
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
|
||||
);
|
||||
EXPECT_FALSE(i_manifest_controller->updateManifest(file_name));
|
||||
}
|
||||
|
||||
@@ -710,10 +704,6 @@ TEST_F(ManifestControllerTest, selfUpdateWithOldCopyWithError)
|
||||
string hostname = "hostname";
|
||||
string empty_err;
|
||||
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err));
|
||||
EXPECT_CALL(
|
||||
mock_status,
|
||||
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
|
||||
);
|
||||
load(manifest, new_services);
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools,
|
||||
@@ -932,10 +922,6 @@ TEST_F(ManifestControllerTest, badInstall)
|
||||
string empty_err;
|
||||
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(empty_err));
|
||||
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return( Maybe<string>(hostname)));
|
||||
EXPECT_CALL(
|
||||
mock_status,
|
||||
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
|
||||
);
|
||||
|
||||
string corrupted_packages_manifest =
|
||||
"{"
|
||||
@@ -1008,12 +994,6 @@ TEST_F(ManifestControllerTest, failToDownloadWithselfUpdate)
|
||||
doesFileExist("/etc/cp/packages/orchestration/orchestration")
|
||||
).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname")));
|
||||
EXPECT_CALL(
|
||||
mock_status,
|
||||
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
|
||||
);
|
||||
string not_error;
|
||||
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error));
|
||||
EXPECT_FALSE(i_manifest_controller->updateManifest(file_name));
|
||||
}
|
||||
|
||||
@@ -1404,12 +1384,6 @@ TEST_F(ManifestControllerTest, failureOnDownloadSharedObject)
|
||||
).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname")));
|
||||
EXPECT_CALL(mock_orchestration_tools, removeFile("/tmp/temp_file1")).WillOnce(Return(true));
|
||||
EXPECT_CALL(
|
||||
mock_status,
|
||||
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
|
||||
);
|
||||
string not_error;
|
||||
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error));
|
||||
|
||||
EXPECT_FALSE(i_manifest_controller->updateManifest(file_name));
|
||||
}
|
||||
@@ -2538,12 +2512,6 @@ TEST_F(ManifestDownloadTest, download_relative_path)
|
||||
doesFileExist("/etc/cp/packages/orchestration/orchestration")
|
||||
).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname")));
|
||||
EXPECT_CALL(
|
||||
mock_status,
|
||||
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
|
||||
);
|
||||
string not_error;
|
||||
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error));
|
||||
|
||||
EXPECT_FALSE(i_manifest_controller->updateManifest(manifest_file.fname));
|
||||
}
|
||||
@@ -2589,8 +2557,6 @@ TEST_F(ManifestDownloadTest, download_relative_path_no_fog_domain)
|
||||
mock_orchestration_tools,
|
||||
doesFileExist("/etc/cp/packages/orchestration/orchestration")
|
||||
).WillOnce(Return(false));
|
||||
string not_error;
|
||||
EXPECT_CALL(mock_status, getManifestError()).WillOnce(ReturnRef(not_error));
|
||||
|
||||
checkIfFileExistsCall(new_packages.at("orchestration"));
|
||||
|
||||
@@ -2604,10 +2570,6 @@ TEST_F(ManifestDownloadTest, download_relative_path_no_fog_domain)
|
||||
)
|
||||
).WillOnce(Return(downloaded_package));
|
||||
EXPECT_CALL(mock_details_resolver, getHostname()).WillOnce(Return(string("hostname")));
|
||||
EXPECT_CALL(
|
||||
mock_status,
|
||||
setFieldStatus(OrchestrationStatusFieldType::MANIFEST, OrchestrationStatusResult::FAILED, _)
|
||||
);
|
||||
|
||||
EXPECT_FALSE(i_manifest_controller->updateManifest(manifest_file.fname));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "config.h"
|
||||
#include "agent_details.h"
|
||||
#include "orchestration_comp.h"
|
||||
#include "updates_process_event.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -174,14 +175,13 @@ ManifestHandler::downloadPackages(const map<string, Package> &new_packages_to_do
|
||||
" software update failed. Agent is running previous software. Contact Check Point support.";
|
||||
}
|
||||
|
||||
auto orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<ManifestHandler>();
|
||||
if (orchestration_status->getManifestError().find("Gateway was not fully deployed") == string::npos) {
|
||||
orchestration_status->setFieldStatus(
|
||||
OrchestrationStatusFieldType::MANIFEST,
|
||||
OrchestrationStatusResult::FAILED,
|
||||
install_error
|
||||
);
|
||||
}
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::DOWNLOAD_FILE,
|
||||
package.getName(),
|
||||
install_error
|
||||
).notify();
|
||||
return genError(
|
||||
"Failed to download installation package. Package: " +
|
||||
package.getName() +
|
||||
@@ -219,11 +219,13 @@ ManifestHandler::installPackage(
|
||||
err_hostname +
|
||||
" software update failed. Agent is running previous software. Contact Check Point support.";
|
||||
if (orchestration_status->getManifestError().find("Gateway was not fully deployed") == string::npos) {
|
||||
orchestration_status->setFieldStatus(
|
||||
OrchestrationStatusFieldType::MANIFEST,
|
||||
OrchestrationStatusResult::FAILED,
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::INSTALL_PACKAGE,
|
||||
package_name,
|
||||
install_error
|
||||
);
|
||||
).notify();
|
||||
}
|
||||
}
|
||||
return self_update_status;
|
||||
@@ -289,11 +291,13 @@ ManifestHandler::installPackage(
|
||||
|
||||
auto orchestration_status = Singleton::Consume<I_OrchestrationStatus>::by<ManifestHandler>();
|
||||
if (orchestration_status->getManifestError().find("Gateway was not fully deployed") == string::npos) {
|
||||
orchestration_status->setFieldStatus(
|
||||
OrchestrationStatusFieldType::MANIFEST,
|
||||
OrchestrationStatusResult::FAILED,
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::INSTALL_PACKAGE,
|
||||
package_name,
|
||||
install_error
|
||||
);
|
||||
).notify();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ TEST_F(PolicyTest, serialization)
|
||||
ASSERT_TRUE(false) << "Cereal threw an exception: " << e.what();
|
||||
}
|
||||
|
||||
EXPECT_EQ(15u, orchestration_policy.getErrorSleepInterval());
|
||||
EXPECT_EQ(20u, orchestration_policy.getSleepInterval());
|
||||
EXPECT_EQ(15, orchestration_policy.getErrorSleepInterval());
|
||||
EXPECT_EQ(20, orchestration_policy.getSleepInterval());
|
||||
EXPECT_EQ("http://10.0.0.18:81/control/", orchestration_policy.getFogAddress());
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ TEST_F(PolicyTest, noAgentType)
|
||||
ASSERT_TRUE(false) << "Cereal threw an exception: " << e.what();
|
||||
}
|
||||
|
||||
EXPECT_EQ(15u, orchestration_policy.getErrorSleepInterval());
|
||||
EXPECT_EQ(20u, orchestration_policy.getSleepInterval());
|
||||
EXPECT_EQ(15, orchestration_policy.getErrorSleepInterval());
|
||||
EXPECT_EQ(20, orchestration_policy.getSleepInterval());
|
||||
EXPECT_EQ("http://10.0.0.18:81/control/", orchestration_policy.getFogAddress());
|
||||
}
|
||||
|
||||
@@ -83,8 +83,8 @@ TEST_F(PolicyTest, zeroSleepIntervels)
|
||||
ASSERT_TRUE(false) << "Cereal threw an exception: " << e.what();
|
||||
}
|
||||
|
||||
EXPECT_EQ(0u, orchestration_policy.getErrorSleepInterval());
|
||||
EXPECT_EQ(0u, orchestration_policy.getSleepInterval());
|
||||
EXPECT_EQ(0, orchestration_policy.getErrorSleepInterval());
|
||||
EXPECT_EQ(0, orchestration_policy.getSleepInterval());
|
||||
EXPECT_EQ("http://10.0.0.18:81/control/", orchestration_policy.getFogAddress());
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ TEST_F(PolicyTest, newOptionalFields)
|
||||
ASSERT_TRUE(false) << "Cereal threw an exception: " << e.what();
|
||||
}
|
||||
|
||||
EXPECT_EQ(10u, orchestration_policy.getErrorSleepInterval());
|
||||
EXPECT_EQ(30u, orchestration_policy.getSleepInterval());
|
||||
EXPECT_EQ(10, orchestration_policy.getErrorSleepInterval());
|
||||
EXPECT_EQ(30, orchestration_policy.getSleepInterval());
|
||||
EXPECT_EQ("https://fog-api-gw-agents.cloud.ngen.checkpoint.com", orchestration_policy.getFogAddress());
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "mock/mock_agent_details.h"
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_rest_api.h"
|
||||
#include "updates_process_event.h"
|
||||
|
||||
using namespace testing;
|
||||
using namespace std;
|
||||
@@ -200,6 +201,19 @@ TEST_F(OrchestrationStatusTest, checkUpdateStatus)
|
||||
auto result = orchestrationStatusFileToString();
|
||||
EXPECT_EQ(buildOrchestrationStatusJSON("attempt time", "Succeeded ", "current time"), result);
|
||||
}
|
||||
TEST_F(OrchestrationStatusTest, checkUpdateStatusByRaiseEvent)
|
||||
{
|
||||
init();
|
||||
EXPECT_CALL(time, getLocalTimeStr())
|
||||
.WillOnce(Return(string("attempt time")))
|
||||
.WillOnce(Return(string("current time")));
|
||||
|
||||
i_orchestration_status->setLastUpdateAttempt();
|
||||
|
||||
UpdatesProcessEvent(UpdatesProcessResult::SUCCESS, UpdatesConfigType::GENERAL).notify();
|
||||
auto result = orchestrationStatusFileToString();
|
||||
EXPECT_EQ(buildOrchestrationStatusJSON("attempt time", "Succeeded ", "current time"), result);
|
||||
}
|
||||
|
||||
TEST_F(OrchestrationStatusTest, recoveryFields)
|
||||
{
|
||||
@@ -482,3 +496,69 @@ TEST_F(OrchestrationStatusTest, setAllFields)
|
||||
EXPECT_EQ(i_orchestration_status->getServiceSettings(), service_map_a);
|
||||
EXPECT_EQ(i_orchestration_status->getRegistrationDetails(), agent_details);
|
||||
}
|
||||
|
||||
TEST_F(OrchestrationStatusTest, checkErrorByRaiseEvent)
|
||||
{
|
||||
init();
|
||||
string fog_address = "http://fog.address";
|
||||
string registar_error = "Fail to registar";
|
||||
string manifest_error = "Fail to achieve manifest";
|
||||
string last_update_error = "Fail to update";
|
||||
|
||||
EXPECT_CALL(time, getLocalTimeStr()).Times(3).WillRepeatedly(Return(string("Time")));
|
||||
|
||||
UpdatesProcessEvent(UpdatesProcessResult::SUCCESS, UpdatesConfigType::GENERAL).notify();
|
||||
i_orchestration_status->setIsConfigurationUpdated(
|
||||
EnumArray<OrchestrationStatusConfigType, bool>(true, true, true)
|
||||
);
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::GENERAL,
|
||||
UpdatesFailureReason::NONE,
|
||||
"",
|
||||
last_update_error
|
||||
).notify();
|
||||
i_orchestration_status->setIsConfigurationUpdated(
|
||||
EnumArray<OrchestrationStatusConfigType, bool>(false, false, false)
|
||||
);
|
||||
|
||||
i_orchestration_status->setUpgradeMode("Online upgrades");
|
||||
i_orchestration_status->setFogAddress(fog_address);
|
||||
|
||||
i_orchestration_status->setUpgradeMode("Online upgrades");
|
||||
i_orchestration_status->setFogAddress(fog_address);
|
||||
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::GENERAL,
|
||||
UpdatesFailureReason::REGISTRATION,
|
||||
"",
|
||||
registar_error
|
||||
).notify();
|
||||
UpdatesProcessEvent(
|
||||
UpdatesProcessResult::FAILED,
|
||||
UpdatesConfigType::MANIFEST,
|
||||
UpdatesFailureReason::NONE,
|
||||
"",
|
||||
manifest_error
|
||||
).notify();
|
||||
EXPECT_EQ(i_orchestration_status->getManifestError(), manifest_error);
|
||||
|
||||
auto result = orchestrationStatusFileToString();
|
||||
EXPECT_EQ(
|
||||
buildOrchestrationStatusJSON(
|
||||
"None",
|
||||
"Failed. Reason: " + last_update_error,
|
||||
"Time",
|
||||
"Time",
|
||||
"",
|
||||
"Time",
|
||||
"Time",
|
||||
"Online upgrades",
|
||||
fog_address,
|
||||
"Failed. Reason: Registration failed. Error: " + registar_error,
|
||||
"Failed. Reason: " + manifest_error
|
||||
),
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,15 @@ TEST_F(URLParserTest, parseAWSWithoutSlash)
|
||||
EXPECT_EQ("", link.getQuery());
|
||||
}
|
||||
|
||||
TEST_F(URLParserTest, setHost)
|
||||
{
|
||||
URLParser link("http://172.23.92.180:180/something");
|
||||
|
||||
EXPECT_EQ(link.getHost(), "172.23.92.180");
|
||||
link.setHost("my.domain");
|
||||
EXPECT_EQ(link.getHost(), "my.domain");
|
||||
}
|
||||
|
||||
TEST_F(URLParserTest, protocolIsMissing)
|
||||
{
|
||||
// HTTPS is set by default when protocol is not present in URL.
|
||||
|
||||
@@ -22,13 +22,13 @@ OrchestrationPolicy::getFogAddress() const
|
||||
return fog_address;
|
||||
}
|
||||
|
||||
const unsigned long &
|
||||
unsigned int
|
||||
OrchestrationPolicy::getSleepInterval() const
|
||||
{
|
||||
return sleep_interval;
|
||||
}
|
||||
|
||||
const unsigned long &
|
||||
unsigned int
|
||||
OrchestrationPolicy::getErrorSleepInterval() const
|
||||
{
|
||||
return error_sleep_interval;
|
||||
@@ -37,10 +37,13 @@ OrchestrationPolicy::getErrorSleepInterval() const
|
||||
void
|
||||
OrchestrationPolicy::serialize(JSONInputArchive &archive)
|
||||
{
|
||||
// Split it, so the order doesn't matter.
|
||||
archive(make_nvp("fog-address", fog_address));
|
||||
archive(make_nvp("pulling-interval", sleep_interval));
|
||||
archive(make_nvp("error-pulling-interval", error_sleep_interval));
|
||||
try {
|
||||
archive(make_nvp("fog-address", fog_address));
|
||||
archive(make_nvp("pulling-interval", sleep_interval));
|
||||
archive(make_nvp("error-pulling-interval", error_sleep_interval));
|
||||
} catch (const cereal::Exception&) {
|
||||
archive(make_nvp("orchestration", *this));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "config.h"
|
||||
#include "updates_process_event.h"
|
||||
#include "health_check_status/health_check_status.h"
|
||||
|
||||
using namespace cereal;
|
||||
using namespace std;
|
||||
@@ -383,7 +385,10 @@ private:
|
||||
map<string, string> service_settings;
|
||||
};
|
||||
|
||||
class OrchestrationStatus::Impl : Singleton::Provide<I_OrchestrationStatus>::From<OrchestrationStatus>
|
||||
class OrchestrationStatus::Impl
|
||||
:
|
||||
Singleton::Provide<I_OrchestrationStatus>::From<OrchestrationStatus>,
|
||||
public Listener<UpdatesProcessEvent>
|
||||
{
|
||||
public:
|
||||
void
|
||||
@@ -399,7 +404,6 @@ public:
|
||||
if (!write_result) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to write Orchestration status. File: " << orchestration_status_path;
|
||||
}
|
||||
dbgTrace(D_ORCHESTRATOR) << "Orchestration status file has been updated. File: " << orchestration_status_path;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -459,11 +463,17 @@ public:
|
||||
seconds(5),
|
||||
[this] ()
|
||||
{
|
||||
dbgTrace(D_ORCHESTRATOR) << "Write Orchestration status file <co-routine>";
|
||||
writeStatusToFile();
|
||||
},
|
||||
"Write Orchestration status file"
|
||||
);
|
||||
registerListener();
|
||||
}
|
||||
|
||||
void
|
||||
upon(const UpdatesProcessEvent &event) override
|
||||
{
|
||||
setFieldStatus(event.getStatusFieldType(), event.getOrchestrationStatusResult(), event.parseDescription());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -129,6 +129,18 @@ URLParser::parseProtocol(const string &url) const
|
||||
return URLProtocol::HTTPS;
|
||||
}
|
||||
|
||||
string
|
||||
URLParser::getHost() const
|
||||
{
|
||||
return host.empty() ? base_url : host;
|
||||
}
|
||||
|
||||
void
|
||||
URLParser::setHost(const string &new_host)
|
||||
{
|
||||
host = new_host;
|
||||
}
|
||||
|
||||
void
|
||||
URLParser::setQuery(const string &new_query)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user