Compare commits

...

66 Commits

Author SHA1 Message Date
Ned Wright
69063463d1 sync code 2024-09-13 08:59:25 +00:00
Ned Wright
f4bad4c4d9 Remove non-active files 2024-09-02 14:16:01 +03:00
WrightNed
6e916599d9 Merge pull request #179 from openappsec/Aug_20_2024-Dev
Aug 20th update
2024-08-27 12:33:46 +03:00
orianelou
24d53aed53 Update docker-compose.yaml 2024-08-27 10:50:25 +03:00
WrightNed
93fb3da2f8 Merge pull request #177 from wiaam96/patch-1
Update entry.sh
2024-08-22 15:17:49 +03:00
wiaam96
e7378c9a5f Update entry.sh 2024-08-22 15:15:24 +03:00
Ned Wright
110f0c8bd2 Aug 20th update 2024-08-21 08:42:14 +00:00
WrightNed
ca31aac08a Merge pull request #174 from openappsec/orianelou-patch-6
Update docker-compose.yaml
2024-08-20 15:17:02 +03:00
orianelou
161b6dd180 Update docker-compose.yaml 2024-08-20 14:50:01 +03:00
WrightNed
84327e0b19 Merge pull request #170 from openappsec/orianelou-patch-4
Create docker-compose.yaml
2024-08-05 13:12:40 +03:00
orianelou
b9723ba6ce Create docker-compose.yaml
added compose for docker SWAG
2024-08-05 12:06:37 +03:00
WrightNed
00e183b8c6 Merge pull request #169 from openappsec/Jul_31_2024-Dev
Jul 31st update
2024-08-01 18:10:44 +03:00
WrightNed
e859c167ed Merge pull request #167 from openappsec/orianelou-crds
Orianelou crds
2024-08-01 18:10:11 +03:00
Ned Wright
384b59cc87 Jul 31st update 2024-07-31 17:15:35 +00:00
orianelou
805e958cb9 Create open-appsec-crd-latest.yaml 2024-07-25 12:06:59 +03:00
orianelou
5bcd7cfcf1 Create open-appsec-crd-v1beta2.yaml 2024-07-25 12:05:57 +03:00
orianelou
ae6f2faeec Create open-appsec-crd-v1beta1.yaml 2024-07-25 12:04:22 +03:00
WrightNed
705a5e6061 Merge pull request #166 from openappsec/Jul_23_2024-Dev
Jul 23rd update
2024-07-24 16:01:45 +03:00
WrightNed
c33b74a970 Merge pull request #164 from chkp-omris/main
update intelligence
2024-07-24 15:54:58 +03:00
chkp-omris
2da9fbc385 update intelligence 2024-07-23 13:15:33 +00:00
Ned Wright
f58e9a6128 Jul 23rd update 2024-07-23 11:08:24 +00:00
WrightNed
57ea5c72c5 Merge pull request #156 from openappsec/Jul_04_2024-Dev
Jul 4th update
2024-07-07 08:47:38 +03:00
Ned Wright
962bd31d46 Jul 4th update 2024-07-04 14:10:34 +00:00
WrightNed
01770475ec Merge pull request #153 from openappsec/Jun_26_2024-Dev
June 27th update
2024-07-01 11:42:11 +03:00
Ned Wright
78b114a274 June 27th update 2024-06-27 12:05:38 +00:00
WrightNed
81b1aec487 Merge pull request #148 from openappsec/orianelou-new-policy-files
Orianelou new policy files
2024-06-19 16:18:41 +03:00
orianelou
be6591a670 Update local_policy.yaml 2024-06-17 13:49:48 +03:00
orianelou
663782009c Update local_policy.yaml 2024-06-17 13:49:18 +03:00
orianelou
9392bbb26c Update local_policy.yaml 2024-06-17 13:49:01 +03:00
orianelou
46682bcdce Update local_policy.yaml 2024-06-17 13:48:39 +03:00
orianelou
057bc42375 Update local_policy.yaml 2024-06-17 13:47:24 +03:00
orianelou
88e0ccd308 Rename open-appsec-k8s-default-config-v1beta21.yaml to open-appsec-k8s-default-config-v1beta1.yaml 2024-06-17 13:45:02 +03:00
orianelou
4241b9c574 Create open-appsec-k8s-prevent-config-v1beta2.yaml 2024-06-17 13:44:45 +03:00
orianelou
4af9f18ada Create open-appsec-k8s-default-config-v1beta2.yaml 2024-06-17 13:44:25 +03:00
orianelou
3b533608b1 Create open-appsec-k8s-prevent-config-v1beta1.yaml 2024-06-17 13:42:13 +03:00
orianelou
74bb3086ec Create open-appsec-k8s-default-config-v1beta21.yaml 2024-06-17 13:41:29 +03:00
orianelou
504d1415a5 Create local_policy.yaml 2024-06-17 13:39:40 +03:00
orianelou
18b1b63c42 Create local_policy.yaml 2024-06-17 13:38:31 +03:00
orianelou
ded2a5ffc2 Create local_policy.yaml 2024-06-17 13:36:23 +03:00
orianelou
1254bb37b2 Create local_policy.yaml 2024-06-17 13:34:35 +03:00
orianelou
cf16343caa Create open-appsec-k8s-prevent-config-v1beta2.yaml 2024-06-16 10:56:16 +03:00
orianelou
78c4209406 Rename config/k8s/v1beta2/default/open-appsec-k8s-default-config-v1beta2.yaml to config/k8s/v1beta2/open-appsec-k8s-default-config-v1beta2.yaml 2024-06-16 10:55:23 +03:00
orianelou
3c8672c565 Rename config/k8s/v1beta2/open-appsec-k8s-default-config-v1beta2.yaml to config/k8s/v1beta2/default/open-appsec-k8s-default-config-v1beta2.yaml 2024-06-16 10:54:05 +03:00
orianelou
48d6baed3b Rename config/linux/v1beta2/local_policy.yaml to config/linux/v1beta2/default/local_policy.yaml 2024-06-16 10:44:39 +03:00
orianelou
8770257a60 Create local_policy.yaml for linux prevent 2024-06-16 10:44:21 +03:00
Ned Wright
fd5d093b24 Add --no-upgrade option to docker 2024-06-03 14:19:41 +00:00
WrightNed
d6debf8d8d Merge pull request #141 from openappsec/May_27_2024-Dev
May 27 2024 dev
2024-06-02 10:15:10 +03:00
Ned Wright
395b754575 Add dammy get-cloud-metadata.sh script 2024-05-29 11:01:17 +00:00
Ned Wright
dc000372c4 Turn on optimization by default 2024-05-27 12:05:16 +00:00
Ned Wright
941c641174 Change cloud default logging 2024-05-27 11:56:05 +00:00
Ned Wright
fdc148aa9b May 27 update 2024-05-27 09:05:33 +00:00
orianelou
307fd8897d Rename config/k8s/open-appsec-k8s-default-config-v1beta2.yaml to config/k8s/v1beta2/open-appsec-k8s-default-config-v1beta2.yaml 2024-05-21 15:24:55 +03:00
orianelou
afd2b4930b Create open-appsec-k8s-default-config-v1beta2.yaml 2024-05-21 15:24:33 +03:00
orianelou
1fb9a29223 Create local_policy.yaml 2024-05-21 15:22:54 +03:00
WrightNed
253ca70de6 Merge pull request #136 from chkp-omris/main
Update agent-intelligence-service package
2024-05-19 15:30:22 +03:00
chkp-omris
938f625535 Merge branch 'openappsec:main' into main 2024-05-19 15:21:46 +03:00
chkp-omris
183d14fc55 Update agent-intelligence-service package 2024-05-19 12:21:10 +00:00
WrightNed
1f3d4ed5e1 Merge pull request #135 from openappsec/Apr_21_2024-Dev
Apr 21 2024 dev
2024-05-19 11:08:26 +03:00
WrightNed
fdbd6d3786 Merge pull request #115 from openappsec/orianelou-patch-3
Update docker-compose.yaml
2024-05-19 11:07:22 +03:00
Ned Wright
4504138a4a Change all deployments to embedded 2024-04-22 09:46:50 +00:00
Ned Wright
66ed4a8d81 April 21th 2024 update 2024-04-21 13:57:46 +00:00
WrightNed
189c9209c9 Merge pull request #122 from openappsec/Apr_14_2024-Dev
Apr 14 2024 dev
2024-04-17 12:40:41 +03:00
Ned Wright
1a1580081c Add watchdog changes 2024-04-16 14:06:43 +00:00
Ned Wright
942b2ef8b4 2024 April 14th update 2024-04-14 12:55:54 +00:00
Ned Wright
7a7f65a77a Detect docker on http transaction installation 2024-04-14 11:28:53 +00:00
orianelou
ecbb34bc17 Update docker-compose.yaml
changes comment type
2024-03-21 11:24:12 +02:00
292 changed files with 114756 additions and 71189 deletions

View File

@@ -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")

View File

@@ -155,6 +155,24 @@ getWaitingForVerdictThreadTimeout()
return conf_data.getNumericalValue("waiting_for_verdict_thread_timeout_msec");
}
unsigned int
getMinRetriesForVerdict()
{
return conf_data.getNumericalValue("min_retries_for_verdict");
}
unsigned int
getMaxRetriesForVerdict()
{
return conf_data.getNumericalValue("max_retries_for_verdict");
}
unsigned int
getReqBodySizeTrigger()
{
return conf_data.getNumericalValue("body_size_trigger");
}
int
isIPAddress(c_str ip_str)
{

View File

@@ -63,31 +63,37 @@ TEST_F(HttpAttachmentUtilTest, GetValidAttachmentConfiguration)
"\"waiting_for_verdict_thread_timeout_msec\": 75,\n"
"\"req_header_thread_timeout_msec\": 10,\n"
"\"ip_ranges\": " + createIPRangesString(ip_ranges) + ",\n"
"\"static_resources_path\": \"" + static_resources_path + "\""
"\"static_resources_path\": \"" + static_resources_path + "\",\n"
"\"min_retries_for_verdict\": 1,\n"
"\"max_retries_for_verdict\": 3,\n"
"\"body_size_trigger\": 777\n"
"}\n";
ofstream valid_configuration_file(attachment_configuration_file_name);
valid_configuration_file << valid_configuration;
valid_configuration_file.close();
EXPECT_EQ(initAttachmentConfig(attachment_configuration_file_name.c_str()), 1);
EXPECT_EQ(getDbgLevel(), 2);
EXPECT_EQ(getDbgLevel(), 2u);
EXPECT_EQ(getStaticResourcesPath(), static_resources_path);
EXPECT_EQ(isFailOpenMode(), 0);
EXPECT_EQ(getFailOpenTimeout(), 1234);
EXPECT_EQ(getFailOpenTimeout(), 1234u);
EXPECT_EQ(isFailOpenHoldMode(), 1);
EXPECT_EQ(getFailOpenHoldTimeout(), 4321);
EXPECT_EQ(getFailOpenHoldTimeout(), 4321u);
EXPECT_EQ(isFailOpenOnSessionLimit(), 1);
EXPECT_EQ(getMaxSessionsPerMinute(), 0);
EXPECT_EQ(getNumOfNginxIpcElements(), 200);
EXPECT_EQ(getKeepAliveIntervalMsec(), 10000);
EXPECT_EQ(getResProccessingTimeout(), 420);
EXPECT_EQ(getReqProccessingTimeout(), 42);
EXPECT_EQ(getRegistrationThreadTimeout(), 101);
EXPECT_EQ(getReqHeaderThreadTimeout(), 10);
EXPECT_EQ(getReqBodyThreadTimeout(), 155);
EXPECT_EQ(getResHeaderThreadTimeout(), 1);
EXPECT_EQ(getResBodyThreadTimeout(), 0);
EXPECT_EQ(getWaitingForVerdictThreadTimeout(), 75);
EXPECT_EQ(getMaxSessionsPerMinute(), 0u);
EXPECT_EQ(getNumOfNginxIpcElements(), 200u);
EXPECT_EQ(getKeepAliveIntervalMsec(), 10000u);
EXPECT_EQ(getResProccessingTimeout(), 420u);
EXPECT_EQ(getReqProccessingTimeout(), 42u);
EXPECT_EQ(getRegistrationThreadTimeout(), 101u);
EXPECT_EQ(getReqHeaderThreadTimeout(), 10u);
EXPECT_EQ(getReqBodyThreadTimeout(), 155u);
EXPECT_EQ(getResHeaderThreadTimeout(), 1u);
EXPECT_EQ(getResBodyThreadTimeout(), 0u);
EXPECT_EQ(getMinRetriesForVerdict(), 1u);
EXPECT_EQ(getMaxRetriesForVerdict(), 3u);
EXPECT_EQ(getReqBodySizeTrigger(), 777u);
EXPECT_EQ(getWaitingForVerdictThreadTimeout(), 75u);
EXPECT_EQ(getInspectionMode(), ngx_http_inspection_mode::BLOCKING_THREAD);
EXPECT_EQ(isDebugContext("1.2.3.4", "5.6.7.8", 80, "GET", "test", "/abc"), 1);

View File

@@ -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"

View File

@@ -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"
@@ -41,12 +44,16 @@ while true; do
done
if [ -z $var_token ] && [ $var_mode != "--hybrid_mode" ]; then
echo "Error: Token was not provided as input argument."
exit 1
var_token=$(env | grep 'AGENT_TOKEN=' | cut -d'=' -f2-)
if [ -z $var_token ]; then
echo "Error: Token was not provided as input argument."
exit 1
fi
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 +66,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

View File

@@ -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)

View File

@@ -1698,7 +1698,7 @@ private:
}
};
mainloop->addFileRoutine(
I_MainLoop::RoutineType::RealTime,
I_MainLoop::RoutineType::System,
server_sock,
accept_attachment_routine,
"Nginx Attachment registration listener",

View File

@@ -42,6 +42,7 @@ HttpAttachmentConfig::init()
setNumOfNginxIpcElements();
setDebugByContextValues();
setKeepAliveIntervalMsec();
setRetriesForVerdict();
}
bool
@@ -215,6 +216,31 @@ HttpAttachmentConfig::setFailOpenTimeout()
conf_data.setNumericalValue("nginx_inspection_mode", inspection_mode);
}
void
HttpAttachmentConfig::setRetriesForVerdict()
{
conf_data.setNumericalValue("min_retries_for_verdict", getAttachmentConf<uint>(
3,
"agent.minRetriesForVerdict.nginxModule",
"HTTP manager",
"Min retries for verdict"
));
conf_data.setNumericalValue("max_retries_for_verdict", getAttachmentConf<uint>(
15,
"agent.maxRetriesForVerdict.nginxModule",
"HTTP manager",
"Max retries for verdict"
));
conf_data.setNumericalValue("body_size_trigger", getAttachmentConf<uint>(
200000,
"agent.reqBodySizeTrigger.nginxModule",
"HTTP manager",
"Request body size trigger"
));
}
void
HttpAttachmentConfig::setFailOpenWaitMode()
{

View File

@@ -70,6 +70,8 @@ private:
void setDebugByContextValues();
void setRetriesForVerdict();
WebTriggerConf web_trigger_conf;
HttpAttachmentConfiguration conf_data;
};

View File

@@ -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)

View File

@@ -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");
}

View File

@@ -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> &params)
{
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;
}

View File

@@ -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> &params)
{
for (const string &param : 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> &params)
{
for (const string &param : 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> &params)
{
for (const string &param : 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> &params)
{
for (const string &param : 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> &params)
{
for (const string &param : 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> &params)
{
for (const string &param : 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> &params) : 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;
}

View File

@@ -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> &params)
{
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> &params)
{
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> &params)
{
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> &params)
{
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> &params)
{
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;
}

View File

@@ -1,38 +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/parameter_eval.h"
#include <vector>
#include <string>
#include "generic_rulebase/rulebase_config.h"
#include "config.h"
#include "debug.h"
using namespace std;
string ParameterMatcher::ctx_key = "parameters";
ParameterMatcher::ParameterMatcher(const vector<string> &params)
{
if (params.size() != 1) reportWrongNumberOfParams(ParameterMatcher::getName(), params.size(), 1, 1);
parameter_id = params[0];
}
Maybe<bool, Context::Error>
ParameterMatcher::evalVariable() const
{
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
return rule.ok() && rule.unpack().isParameterActive(parameter_id);
}

View File

@@ -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> &params)
{
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);
}

View File

@@ -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> &params)
{
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;
}

View File

@@ -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> &params)
{
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);
}

View File

@@ -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> &params)
{
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;
}

View File

@@ -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();
}

View File

@@ -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";
}
}
}

View File

@@ -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";
}

View File

@@ -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);
}

View File

@@ -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 &parameter_id) const
{
for (auto param: parameters) {
if (param.getId() == parameter_id) {
return true;
}
}
return false;
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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");
}

View File

@@ -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"
)

View File

@@ -34,6 +34,7 @@ public:
~DetailsResolver();
void preload() override;
void init() override;
private:
class Impl;

View File

@@ -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:

View File

@@ -24,7 +24,8 @@ class ExternalSdkServer
:
public Component,
Singleton::Provide<I_ExternalSdkServer>,
Singleton::Consume<I_RestApi>
Singleton::Consume<I_RestApi>,
Singleton::Consume<I_Messaging>
{
public:
ExternalSdkServer();

View File

@@ -89,7 +89,9 @@ private:
bool matchAttributesRegEx(const std::set<std::string> &values,
std::set<std::string> &matched_override_keywords) const;
bool matchAttributesString(const std::set<std::string> &values) const;
bool matchAttributesIp(const std::set<std::string> &values) const;
bool isRegEx() const;
bool isIP() const;
MatchType type;
Operators operator_type;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View 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,

View File

@@ -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() {}

View File

@@ -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,

View 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();

View File

@@ -40,7 +40,7 @@ public:
~OrchestrationStatus();
void init() override;
private:
class Impl;
std::unique_ptr<Impl> pimpl;

View File

@@ -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();

View File

@@ -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;
};

View File

@@ -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;
};

View File

@@ -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)
{

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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 &ltrim(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])

View File

@@ -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__

View File

@@ -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

View File

@@ -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__

View File

@@ -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)
{

View File

@@ -26,6 +26,8 @@ static const map<string, IPSConfiguration::Context> default_conf_mapping = {
};
static const IPSConfiguration default_conf(default_conf_mapping);
static const IPSSignatures default_ips_sigs;
static const SnortSignatures default_snort_sigs;
IPSEntry::IPSEntry() : TableOpaqueSerialize<IPSEntry>(this) {}
@@ -51,9 +53,9 @@ IPSEntry::respond(const ParsedContext &parsed)
ctx.registerValue(name, buf);
ctx.activate();
auto &signatures = getConfigurationWithDefault(IPSSignatures(), "IPS", "IpsProtections");
auto &signatures = getConfigurationWithDefault(default_ips_sigs, "IPS", "IpsProtections");
bool should_drop = signatures.isMatchedPrevent(parsed.getName(), buf);
auto &snort_signatures = getConfigurationWithDefault(SnortSignatures(), "IPSSnortSigs", "SnortProtections");
auto &snort_signatures = getConfigurationWithDefault(default_snort_sigs, "IPSSnortSigs", "SnortProtections");
should_drop |= snort_signatures.isMatchedPrevent(parsed.getName(), buf);
ctx.deactivate();

View File

@@ -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;

View File

@@ -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\","

View File

@@ -7,7 +7,7 @@ TEST(configuration, basic_context)
IPSConfiguration::Context ctx1(IPSConfiguration::ContextType::HISTORY, 254);
EXPECT_EQ(ctx1.getType(), IPSConfiguration::ContextType::HISTORY);
EXPECT_EQ(ctx1.getHistorySize(), 254);
EXPECT_EQ(ctx1.getHistorySize(), 254u);
IPSConfiguration::Context ctx2(IPSConfiguration::ContextType::NORMAL, 0);
EXPECT_EQ(ctx2.getType(), IPSConfiguration::ContextType::NORMAL);
@@ -42,7 +42,7 @@ TEST(configuration, read_configuration)
auto body = conf.getContext("HTTP_REQUEST_BODY");
EXPECT_EQ(body.getType(), IPSConfiguration::ContextType::HISTORY);
EXPECT_EQ(conf.getHistorySize("HTTP_REQUEST_BODY"), 100);
EXPECT_EQ(conf.getHistorySize("HTTP_REQUEST_BODY"), 100u);
auto header = conf.getContext("HTTP_REQUEST_HEADER");
EXPECT_EQ(header.getType(), IPSConfiguration::ContextType::KEEP);

View File

@@ -137,8 +137,8 @@ private:
TEST_F(EntryTest, basic_inherited_functions)
{
EXPECT_EQ(IPSEntry::name(), "IPS");
EXPECT_EQ(IPSEntry::currVer(), 0);
EXPECT_EQ(IPSEntry::minVer(), 0);
EXPECT_EQ(IPSEntry::currVer(), 0u);
EXPECT_EQ(IPSEntry::minVer(), 0u);
EXPECT_NE(IPSEntry::prototype(), nullptr);
EXPECT_EQ(entry.getListenerName(), IPSEntry::name());

View File

@@ -71,7 +71,7 @@ TEST(resources, basic_resource)
Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(resource);
auto loaded_resources = getSettingWithDefault(IPSSignaturesResource(), "IPS", "protections");
EXPECT_EQ(loaded_resources.getSignatures().size(), 2);
EXPECT_EQ(loaded_resources.getSignatures().size(), 2u);
auto version = getSettingWithDefault<string>("", "IPS", "VersionId");
EXPECT_EQ(version, "1234567");
}

View File

@@ -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;

View File

@@ -385,8 +385,29 @@ Layer7AccessControl::Impl::init()
i_intelligence = Singleton::Consume<I_Intelligence_IS_V2>::by<Layer7AccessControl>();
i_mainloop = Singleton::Consume<I_MainLoop>::by<Layer7AccessControl>();
chrono::minutes expiration(
getProfileAgentSettingWithDefault<uint>(60u, "layer7AccessControl.crowdsec.cacheExpiration")
int cache_expiration_in_seconds = 30;
string cache_expiration_env = getenv("CROWDSEC_CACHE_EXPIRATION") ? getenv("CROWDSEC_CACHE_EXPIRATION") : "";
if (!cache_expiration_env.empty()) {
if (
all_of(cache_expiration_env.begin(), cache_expiration_env.end(), ::isdigit)
&& stoi(cache_expiration_env) > 0
) {
cache_expiration_in_seconds = stoi(cache_expiration_env);
dbgInfo(D_L7_ACCESS_CONTROL)
<< "Successfully read cache expiration value from env: "
<< cache_expiration_env;
} else {
dbgWarning(D_L7_ACCESS_CONTROL)
<< "An invalid cache expiration value was provided in env: "
<< cache_expiration_env;
}
}
chrono::seconds expiration(
getProfileAgentSettingWithDefault<uint>(
cache_expiration_in_seconds,
"layer7AccessControl.crowdsec.cacheExpiration"
)
);
ip_reputation_cache.startExpiration(

View File

@@ -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\": ["
@@ -240,7 +247,9 @@ Layer7AccessControlTest::verifyReport(
string log = reportToStr(report);
dbgTrace(D_L7_ACCESS_CONTROL) << "Report: " << log;
if (!source_identifier.empty()) EXPECT_THAT(log, HasSubstr("\"httpSourceId\": \"" + source_identifier + "\""));
if (!source_identifier.empty()) {
EXPECT_THAT(log, HasSubstr("\"httpSourceId\": \"" + source_identifier + "\""));
}
EXPECT_THAT(log, HasSubstr("\"securityAction\": \"" + security_action + "\""));
EXPECT_THAT(log, HasSubstr("\"eventName\": \"Access Control External Vendor Reputation\""));
EXPECT_THAT(log, HasSubstr("\"httpHostName\": \"juice-shop.checkpoint.com\""));
@@ -259,7 +268,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 +314,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 +360,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 +412,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 +458,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");

View File

@@ -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

View File

@@ -404,6 +404,7 @@ AppsecPracticeAntiBotSection::save(cereal::JSONOutputArchive &out_ar) const
}
// LCOV_EXCL_START Reason: no test exist
// Used for V1Beta1
WebAppSection::WebAppSection(
const string &_application_urls,
const string &_asset_id,
@@ -417,7 +418,7 @@ WebAppSection::WebAppSection(
const LogTriggerSection &parsed_log_trigger,
const string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources,
const vector<InnerException> &parsed_exceptions)
const std::map<std::string, std::vector<InnerException>> &exceptions)
:
application_urls(_application_urls),
asset_id(_asset_id),
@@ -449,8 +450,11 @@ WebAppSection::WebAppSection(
overrides.push_back(AppSecOverride(source_ident));
}
for (const InnerException &exception : parsed_exceptions) {
overrides.push_back(AppSecOverride(exception));
for (const auto &exception : exceptions) {
for (const auto &inner_exception : exception.second) {
overrides.push_back(AppSecOverride(inner_exception));
}
}
}

View File

@@ -146,7 +146,9 @@ AppsecException::load(cereal::JSONInputArchive &archive_in)
{
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec exception";
parseAppsecJSONKey<string>("name", name, archive_in);
archive_in(CEREAL_NVP(exception_spec));
AppsecExceptionSpec single_exception_spec;
single_exception_spec.load(archive_in);
exception_spec.push_back(single_exception_spec);
}
void
@@ -174,7 +176,7 @@ ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception)
{
bool single_condition = parsed_exception.isOneCondition();
for (auto &attrib : attributes) {
auto &attrib_name = attrib.first;
auto attrib_name = (attrib.first == "sourceIp" ? "sourceIP" : attrib.first);
auto &attrib_getter = attrib.second;
auto exceptions_value = attrib_getter(parsed_exception);
if (exceptions_value.empty()) continue;

View File

@@ -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__

View File

@@ -275,7 +275,7 @@ public:
const LogTriggerSection &parsed_log_trigger,
const std::string &default_mode,
const AppSecTrustedSources &parsed_trusted_sources,
const std::vector<InnerException> &parsed_exceptions
const std::map<std::string, std::vector<InnerException>> &exceptions
);
// used for V1beta2

View File

@@ -44,7 +44,7 @@ public:
bool isOneCondition() const;
private:
int conditions_number;
int conditions_number = 0;
std::string action;
std::vector<std::string> country_code;
std::vector<std::string> country_name;

View File

@@ -79,6 +79,7 @@ class DefaultBackend
{
public:
void load(cereal::JSONInputArchive &);
bool doesExist() const;
private:
bool is_exists = false;
@@ -90,6 +91,7 @@ public:
void load(cereal::JSONInputArchive &archive_in);
const std::vector<IngressDefinedRule> & getRules() const;
bool doesDefaultBackendExist() const;
private:
std::string ingress_class_name;

View File

@@ -129,7 +129,7 @@ public:
bool shouldBeautifyLogs() const;
bool getCloud() const;
bool isK8SNeeded() const;
bool isContainerNeeded() const;
bool isCefNeeded() const;
bool isSyslogNeeded() const;
const std::string & getSyslogServerIpv4Address() const;
@@ -140,7 +140,7 @@ private:
const NewLoggingService & getCefServiceData() const;
bool cloud = false;
bool k8s_service = false;
bool container_service = false;
bool agent_local = true;
bool beautify_logs = true;
NewLoggingService syslog_service;

View File

@@ -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__

View File

@@ -111,7 +111,7 @@ private:
SecurityAppsWrapper security_apps;
};
class PolicyMakerUtils
class PolicyMakerUtils : Singleton::Consume<I_EnvDetails>
{
public:
std::string proccesSingleAppsecPolicy(

View File

@@ -39,7 +39,7 @@ public:
bool _logToAgent,
bool _logToCef,
bool _logToCloud,
bool _logToK8sService,
bool _logToContainerService,
bool _logToSyslog,
bool _responseBody,
bool _tpDetect,
@@ -73,7 +73,7 @@ private:
bool logToAgent;
bool logToCef;
bool logToCloud;
bool logToK8sService;
bool logToContainerService;
bool logToSyslog;
bool responseBody;
bool tpDetect;
@@ -258,7 +258,7 @@ public:
bool shouldBeautifyLogs() const;
bool getCloud() const;
bool isK8SNeeded() const;
bool isContainerNeeded() const;
bool isCefNeeded() const;
bool isSyslogNeeded() const;
const std::string & getSyslogServerIpv4Address() const;
@@ -269,7 +269,7 @@ private:
const LoggingService & getCefServiceData() const;
bool cloud = false;
bool k8s_service = false;
bool container_service = false;
bool agent_local = true;
bool beautify_logs = true;
LoggingService syslog_service;

View File

@@ -86,6 +86,12 @@ DefaultBackend::load(cereal::JSONInputArchive &)
is_exists = true;
}
bool
DefaultBackend::doesExist() const
{
return is_exists;
}
void
IngressSpec::load(cereal::JSONInputArchive &archive_in)
{
@@ -101,6 +107,12 @@ IngressSpec::getRules() const
return rules;
}
bool
IngressSpec::doesDefaultBackendExist() const
{
return default_backend.doesExist();
}
void
SingleIngressData::load(cereal::JSONInputArchive &archive_in)
{

View File

@@ -532,25 +532,37 @@ K8sPolicyUtils::createPolicy(
map<AnnotationKeys, string> &annotations_values,
const SingleIngressData &item) const
{
if (policies.find(annotations_values[AnnotationKeys::PolicyKey]) == policies.end()) {
policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy;
}
if (item.getSpec().doesDefaultBackendExist()) {
dbgTrace(D_LOCAL_POLICY)
<< "Inserting Any host rule to the specific asset set";
K ingress_rule = K("*");
policies[annotations_values[AnnotationKeys::PolicyKey]].addSpecificRule(ingress_rule);
}
for (const IngressDefinedRule &rule : item.getSpec().getRules()) {
string url = rule.getHost();
string host = rule.getHost();
for (const IngressRulePath &uri : rule.getPathsWrapper().getRulePaths()) {
if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(url + uri.getPath())) {
if (uri.getPath() != "/") {
host = host + uri.getPath();
}
if (!appsec_policy.getAppsecPolicySpec().isAssetHostExist(host)) {
dbgTrace(D_LOCAL_POLICY)
<< "Inserting Host data to the specific asset set:"
<< "URL: '"
<< url
<< rule.getHost()
<< "' uri: '"
<< uri.getPath()
<< "'";
K ingress_rule = K(url + uri.getPath());
appsec_policy.addSpecificRule(ingress_rule);
K ingress_rule = K(host);
policies[annotations_values[AnnotationKeys::PolicyKey]].addSpecificRule(ingress_rule);
}
}
}
policies[annotations_values[AnnotationKeys::PolicyKey]] = appsec_policy;
}
}
std::tuple<map<string, AppsecLinuxPolicy>, map<string, V1beta2AppsecLinuxPolicy>>
K8sPolicyUtils::createAppsecPoliciesFromIngresses()

View File

@@ -126,6 +126,7 @@ NewAppsecPolicySpec::load(cereal::JSONInputArchive &archive_in)
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec policy spec";
parseAppsecJSONKey<string>("appsecClassName", appsec_class_name, archive_in);
parseAppsecJSONKey<NewParsedRule>("default", default_rule, archive_in);
default_rule.setHost("*");
parseAppsecJSONKey<vector<NewParsedRule>>("specificRules", specific_rules, archive_in);
}

View File

@@ -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,16 +174,22 @@ 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);
parseAppsecJSONKey<bool>("k8s-service", k8s_service, archive_in, k8s_service_default);
// BC try load previous name. TODO: update CRD
parseAppsecJSONKey<bool>("k8s-service", container_service, archive_in, k8s_service_default);
parseAppsecJSONKey<bool>("container-service", container_service, archive_in, container_service);
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);
@@ -221,9 +226,9 @@ NewAppsecTriggerLogDestination::getCloud() const
}
bool
NewAppsecTriggerLogDestination::isK8SNeeded() const
NewAppsecTriggerLogDestination::isContainerNeeded() const
{
return k8s_service;
return container_service;
}
bool

View File

@@ -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

View File

@@ -21,6 +21,7 @@
using namespace std;
USE_DEBUG_FLAG(D_NGINX_POLICY);
USE_DEBUG_FLAG(D_LOCAL_POLICY);
void
SecurityAppsWrapper::save(cereal::JSONOutputArchive &out_ar) const
@@ -147,7 +148,7 @@ string
PolicyMakerUtils::dumpPolicyToFile(
const PolicyWrapper &policy,
const string &policy_path,
const string &settings_path)
const string &)
{
clearElementsMaps();
@@ -170,6 +171,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,10 +181,38 @@ 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;
}
template<class R>
vector<string>
extractExceptionAnnotationNames(
const R &parsed_rule,
const R &default_rule,
const string &policy_name)
{
vector<string> annotation_names;
const R &rule = (!parsed_rule.getExceptions().empty() ? parsed_rule : default_rule);
for (const string &exception_name : rule.getExceptions()) {
if (exception_name.empty()) {
continue;
}
const auto policy_exception = policy_name + "/" + exception_name;
dbgTrace(D_NGINX_POLICY) << "Adding " << policy_exception << " to exception vector";
annotation_names.push_back(policy_exception);
}
dbgTrace(D_NGINX_POLICY) << "Number of exceptions related to rule: " << annotation_names.size();
return annotation_names;
}
template<class R>
map<AnnotationTypes, string>
extractAnnotationsNames(
@@ -215,18 +245,6 @@ extractAnnotationsNames(
rule_annotation[AnnotationTypes::TRIGGER] = policy_name + "/" + trigger_annotation_name;
}
string exception_annotation_name;
// TBD: support multiple exceptions
if (!parsed_rule.getExceptions().empty() && !parsed_rule.getExceptions()[0].empty()) {
exception_annotation_name = parsed_rule.getExceptions()[0];
} else if (!default_rule.getExceptions().empty() && !default_rule.getExceptions()[0].empty()) {
exception_annotation_name = default_rule.getExceptions()[0];
}
if (!exception_annotation_name.empty()) {
rule_annotation[AnnotationTypes::EXCEPTION] = policy_name + "/" + exception_annotation_name;
}
string web_user_res_annotation_name =
parsed_rule.getCustomResponse().empty() ?
default_rule.getCustomResponse() :
@@ -442,6 +460,7 @@ template<class T, class R>
R
getAppsecExceptionSpec(const string &exception_annotation_name, const T &policy)
{
dbgFlow(D_NGINX_POLICY) << "anotation name: " << exception_annotation_name;
auto exceptions_vec = policy.getAppsecExceptions();
auto exception_it = extractElement(exceptions_vec.begin(), exceptions_vec.end(), exception_annotation_name);
@@ -536,7 +555,7 @@ extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_sp
bool webHeaders = trigger_spec.getAppsecTriggerExtendedLogging().isHttpHeaders();
bool webBody = trigger_spec.getAppsecTriggerExtendedLogging().isRequestBody();
bool logToCloud = trigger_spec.getAppsecTriggerLogDestination().getCloud();
bool logToK8sService = trigger_spec.getAppsecTriggerLogDestination().isK8SNeeded();
bool logToContainerService = trigger_spec.getAppsecTriggerLogDestination().isContainerNeeded();
bool logToAgent = trigger_spec.getAppsecTriggerLogDestination().isAgentLocal();
bool beautify_logs = trigger_spec.getAppsecTriggerLogDestination().shouldBeautifyLogs();
bool logToCef = trigger_spec.getAppsecTriggerLogDestination().isCefNeeded();
@@ -563,7 +582,7 @@ extractLogTriggerData(const string &trigger_annotation_name, const T &trigger_sp
logToAgent,
logToCef,
logToCloud,
logToK8sService,
logToContainerService,
logToSyslog,
responseBody,
tpDetect,
@@ -774,6 +793,7 @@ createExceptionSection(
const string &exception_annotation_name,
const T &policy)
{
dbgFlow(D_NGINX_POLICY) << "exception annotation name" << exception_annotation_name;
AppsecException exception_spec =
getAppsecExceptionSpec<T, AppsecException>(exception_annotation_name, policy);
vector<InnerException> res;
@@ -782,6 +802,7 @@ createExceptionSection(
ExceptionBehavior exception_behavior(exception.getAction());
res.push_back(InnerException(exception_behavior, exception_match));
}
return res;
}
@@ -894,13 +915,16 @@ createMultiRulesSections(
const string &web_user_res_vec_id,
const string &web_user_res_vec_type,
const string &asset_name,
const string &exception_name,
const vector<InnerException> &exceptions)
const std::map<std::string, std::vector<InnerException>> &exceptions)
{
PracticeSection practice = PracticeSection(practice_id, practice_type, practice_name);
vector<ParametersSection> exceptions_result;
for (auto exception : exceptions) {
exceptions_result.push_back(ParametersSection(exception.getBehaviorId(), exception_name));
const auto &exception_name = exception.first;
for (const auto &inner_exception : exception.second) {
exceptions_result.push_back(ParametersSection(inner_exception.getBehaviorId(), exception_name));
}
}
vector<RulesTriggerSection> triggers;
@@ -1002,8 +1026,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 +1101,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 +1155,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 +1197,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 +1217,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 +1234,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]],
@@ -1338,6 +1366,7 @@ PolicyMakerUtils::combineElementsToPolicy(const string &policy_version)
convertMapToVector(log_triggers), convertMapToVector(web_user_res_triggers)
)
);
ExceptionsWrapper exceptions_section({
ExceptionsRulebase(convertExceptionsMapToVector(inner_exceptions))
});
@@ -1375,6 +1404,7 @@ PolicyMakerUtils::createPolicyElementsByRule(
const string &policy_name)
{
map<AnnotationTypes, string> rule_annotations = extractAnnotationsNames(rule, default_rule, policy_name);
if (
!rule_annotations[AnnotationTypes::TRIGGER].empty() &&
!log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER])
@@ -1397,15 +1427,27 @@ PolicyMakerUtils::createPolicyElementsByRule(
);
}
if (
!rule_annotations[AnnotationTypes::EXCEPTION].empty() &&
!inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION])
) {
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] =
createExceptionSection<T>(
rule_annotations[AnnotationTypes::EXCEPTION],
policy
);
const auto exceptions_annotations = extractExceptionAnnotationNames(rule, default_rule, policy_name);
std::map<std::string, std::vector<InnerException>> rule_inner_exceptions;
if (!exceptions_annotations.empty()) {
for (const auto &exception_name :exceptions_annotations) {
dbgWarning(D_LOCAL_POLICY) << "exceptions name: " << exception_name;
if (rule_inner_exceptions.count(exception_name)) {
dbgWarning(D_LOCAL_POLICY) << "exception name already exists for that rule: " << exception_name;
continue;
}
if (inner_exceptions.count(exception_name)) {
dbgWarning(D_LOCAL_POLICY) << "exception name already exists in inner exceptions: " << exception_name;
rule_inner_exceptions[exception_name] = inner_exceptions[exception_name];
continue;
}
auto exception_section = createExceptionSection<T>(exception_name, policy);
rule_inner_exceptions[exception_name] = exception_section;
inner_exceptions[exception_name] = exception_section;
}
}
if (
@@ -1464,8 +1506,7 @@ PolicyMakerUtils::createPolicyElementsByRule(
web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]].getTriggerId(),
"WebUserResponse",
full_url,
rule_annotations[AnnotationTypes::EXCEPTION],
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]]
rule_inner_exceptions
);
rules_config[rule_config.getAssetName()] = rule_config;
@@ -1492,7 +1533,7 @@ PolicyMakerUtils::createPolicyElementsByRule(
log_triggers[rule_annotations[AnnotationTypes::TRIGGER]],
rule.getMode(),
trusted_sources[rule_annotations[AnnotationTypes::TRUSTED_SOURCES]],
inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]]
rule_inner_exceptions
);
web_apps[rule_config.getAssetName()] = web_app;
}
@@ -1630,7 +1671,9 @@ PolicyMakerUtils::createAgentPolicyFromAppsecPolicy(const string &policy_name, c
createPolicyElements<T, R>(specific_rules, default_rule, appsec_policy, policy_name);
// add default rule to policy
createPolicyElementsByRule<T, R>(default_rule, default_rule, appsec_policy, policy_name);
if (Singleton::Consume<I_EnvDetails>::by<PolicyMakerUtils>()->getEnvType() != EnvType::K8S) {
createPolicyElementsByRule<T, R>(default_rule, default_rule, appsec_policy, policy_name);
}
}
// LCOV_EXCL_START Reason: no test exist
@@ -1653,11 +1696,13 @@ PolicyMakerUtils::createAgentPolicyFromAppsecPolicy<V1beta2AppsecLinuxPolicy, Ne
);
// add default rule to policy
createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsedRule>(
default_rule,
default_rule,
appsec_policy,
policy_name);
if (Singleton::Consume<I_EnvDetails>::by<PolicyMakerUtils>()->getEnvType() != EnvType::K8S) {
createPolicyElementsByRule<V1beta2AppsecLinuxPolicy, NewParsedRule>(
default_rule,
default_rule,
appsec_policy,
policy_name);
}
}
// LCOV_EXCL_STOP

View File

@@ -30,7 +30,7 @@ LogTriggerSection::LogTriggerSection(
bool _logToAgent,
bool _logToCef,
bool _logToCloud,
bool _logToK8sService,
bool _logToContainerService,
bool _logToSyslog,
bool _responseBody,
bool _tpDetect,
@@ -55,7 +55,7 @@ LogTriggerSection::LogTriggerSection(
logToAgent(_logToAgent),
logToCef(_logToCef),
logToCloud(_logToCloud),
logToK8sService(_logToK8sService),
logToContainerService(_logToContainerService),
logToSyslog(_logToSyslog),
responseBody(_responseBody),
tpDetect(_tpDetect),
@@ -96,12 +96,12 @@ LogTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
cereal::make_nvp("acDrop", acDrop),
cereal::make_nvp("complianceViolations", false),
cereal::make_nvp("complianceWarnings", false),
cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity),
cereal::make_nvp("extendlogging", extendlogging),
cereal::make_nvp("extendLoggingMinSeverity", extendloggingMinSeverity),
cereal::make_nvp("extendLogging", extendlogging),
cereal::make_nvp("logToAgent", logToAgent),
cereal::make_nvp("logToCef", logToCef),
cereal::make_nvp("logToCloud", logToCloud),
cereal::make_nvp("logToK8sService", logToK8sService),
cereal::make_nvp("logToContainerService", logToContainerService),
cereal::make_nvp("logToSyslog", logToSyslog),
cereal::make_nvp("responseBody", responseBody),
cereal::make_nvp("responseCode", false),
@@ -387,12 +387,18 @@ 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);
parseAppsecJSONKey<bool>("k8s-service", k8s_service, archive_in, k8s_service_default);
// BC try load previous name. TODO: update CRD
parseAppsecJSONKey<bool>("k8s-service", container_service, archive_in, k8s_service_default);
parseAppsecJSONKey<bool>("container-service", container_service, archive_in, container_service);
StdoutLogging stdout_log;
parseAppsecJSONKey<StdoutLogging>("stdout", stdout_log, archive_in);
@@ -433,9 +439,9 @@ AppsecTriggerLogDestination::getCloud() const
}
bool
AppsecTriggerLogDestination::isK8SNeeded() const
AppsecTriggerLogDestination::isContainerNeeded() const
{
return k8s_service;
return container_service;
}
bool

View File

@@ -12,6 +12,9 @@ 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(external_sdk_server)
#add_subdirectory(orchestration_ut)

View File

@@ -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,9 +137,22 @@ 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()) {
dbgDebug(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()
{
#if defined(gaia) || defined(smb)
static const string cmd =
"clish -c 'show version os kernel' | awk '{print $4}' "
"| cut -d '.' -f 1 | awk -F: '{ if ( $1 >= 3 ) {print 1} else {print 0}}'";
@@ -145,12 +161,14 @@ DetailsResolver::Impl::isKernelVersion3OrHigher()
if (is_gogo.ok() && !is_gogo.unpack().empty()) {
return is_gogo.unpack().front() == '1';
}
#endif
return false;
}
bool
DetailsResolver::Impl::isGwNotVsx()
{
#if defined(gaia) || defined(smb)
static const string is_gw_cmd = "cpprod_util FwIsFirewallModule";
static const string is_vsx_cmd = "cpprod_util FWisVSX";
auto is_gw = DetailsResolvingHanlder::getCommandOutput(is_gw_cmd);
@@ -158,6 +176,7 @@ DetailsResolver::Impl::isGwNotVsx()
if (is_gw.ok() && is_vsx.ok() && !is_gw.unpack().empty() && !is_vsx.unpack().empty()) {
return is_gw.unpack().front() == '1' && is_vsx.unpack().front() == '0';
}
#endif
return false;
}
@@ -174,17 +193,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 +304,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()
{

View File

@@ -15,21 +15,36 @@
#define __CHECKPOINT_PRODUCT_HANDLERS_H__
#include <algorithm>
#include <regex>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#if defined(gaia)
Maybe<string>
checkSAMLSupportedBlade(const string &command_output)
{
string supportedBlades[3] = {"identityServer", "vpn", "cvpn"};
// uncomment when vpn will support SAML authentication
// string supportedBlades[3] = {"identityServer", "vpn", "cvpn"};
string supportedBlades[1] = {"identityServer"};
for(const string &blade : supportedBlades) {
if (command_output.find(blade) != string::npos) {
return string("true");
}
}
return genError("Current host does not have SAML capability");
return string("false");
}
Maybe<string>
checkIDABlade(const string &command_output)
{
string idaBlade = "identityServer";
if (command_output.find(idaBlade) != string::npos) {
return string("true");
}
return string("false");
}
Maybe<string>
@@ -39,13 +54,26 @@ checkSAMLPortal(const string &command_output)
return string("true");
}
return genError("Current host does not have SAML Portal configured");
return string("false");
}
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 string("false");
}
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>
@@ -61,7 +89,7 @@ checkIDP(shared_ptr<istream> file_stream)
}
}
return genError("Identity Provider was not found");
return string("false");
}
#endif // gaia
@@ -76,6 +104,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 +132,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 +331,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)

View File

@@ -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

View File

@@ -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,10 +73,33 @@ 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
{
I_ShellCmd *shell = Singleton::Consume<I_ShellCmd>::by<DetailsResolvingHanlder>();
I_AgentDetailsReporter *reporter = Singleton::Consume<I_AgentDetailsReporter>::by<DetailsResolvingHanlder>();
uint32_t timeout = getConfigurationWithDefault<uint32_t>(5000, "orchestration", "Details resolver time out");
for (auto &shell_pre_command : shell_pre_commands) {
@@ -97,7 +123,15 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const
Maybe<string> shell_command_output = getCommandOutput(command);
if (!shell_command_output.ok()) continue;
Maybe<string> handler_ret = handler(*shell_command_output);
if (handler_ret.ok()) resolved_details[attr] = *handler_ret;
if (handler_ret.ok()) {
resolved_details[attr] = *handler_ret;
} else {
if (reporter->isPersistantAttr(attr)) {
dbgTrace(D_AGENT_DETAILS)<< "Persistent attribute changed, removing old value";
reporter->deleteAttr(attr);
}
}
}
for (auto file_handler : file_content_handlers) {
@@ -108,7 +142,7 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const
shared_ptr<ifstream> in_file =
Singleton::Consume<I_OrchestrationTools>::by<DetailsResolvingHanlder>()->fileStreamWrapper(path);
if (!in_file->is_open()) {
dbgWarning(D_AGENT_DETAILS) << "Could not open file for processing. Path: " << path;
dbgDebug(D_AGENT_DETAILS) << "Could not open file for processing. Path: " << path;
continue;
}
@@ -132,7 +166,6 @@ DetailsResolvingHanlder::Impl::getResolvedDetails() const
}
}
I_AgentDetailsReporter *reporter = Singleton::Consume<I_AgentDetailsReporter>::by<DetailsResolvingHanlder>();
reporter->addAttr(resolved_details, true);
return resolved_details;
@@ -155,6 +188,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
{

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -1,3 +1,7 @@
#include <sstream>
class Package;
static std::ostream & operator<<(std::ostream &os, const Package &) { return os; }
#include "cptest.h"
#include "config.h"
#include "config_component.h"
@@ -38,7 +42,7 @@ TEST_F(DownloaderTest, doNothing)
{
}
TEST_F(DownloaderTest, downloadFileFromFog)
TEST_F(DownloaderTest, downloadFile)
{
string fog_response = "bla bla";
string checksum = "123";
@@ -55,7 +59,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 +80,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 +245,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

View 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

View File

@@ -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__

View File

@@ -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

View File

@@ -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__

View File

@@ -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");
}

View File

@@ -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

View File

@@ -0,0 +1,4 @@
include_directories(${PROJECT_SOURCE_DIR}/core/external_sdk/)
add_library(external_sdk_server external_sdk_server.cc)
add_subdirectory(external_sdk_server_ut)

View File

@@ -0,0 +1,348 @@
#include "external_sdk_server.h"
#include "external_agent_sdk.h"
#include "log_generator.h"
#include "rest_server.h"
#include "generic_metric.h"
#include "customized_cereal_map.h"
#include "report/log_rest.h"
using namespace std;
USE_DEBUG_FLAG(D_EXTERNAL_SDK_USER);
USE_DEBUG_FLAG(D_EXTERNAL_SDK_SERVER);
class ExternalSdkRest : public ServerRest
{
public:
void
doCall() override
{
dbgFlow(D_EXTERNAL_SDK_SERVER);
Maybe<SdkApiType> sdk_event_type = convertToEnum<SdkApiType>(event_type.get());
if (!sdk_event_type.ok()) {
dbgWarning(D_EXTERNAL_SDK_SERVER) << "Received illegal event type. Type : " << event_type.get();
throw JsonError("Illegal event type provided");
}
dbgDebug(D_EXTERNAL_SDK_SERVER)
<< "Handling a new external sdk api call event. Type : "
<< convertApiTypeToString(sdk_event_type.unpack());
I_ExternalSdkServer *sdk_server = Singleton::Consume<I_ExternalSdkServer>::from<ExternalSdkServer>();
switch(sdk_event_type.unpack()) {
case SdkApiType::SendCodeEvent: {
if (!file.isActive()) {
throw JsonError("File was not provided for code event");
}
if (!func.isActive()) {
throw JsonError("Function was not provided for code event");
}
if (!line.isActive()) {
throw JsonError("Line path was not provided for code event");
}
if (!trace_id.isActive()) {
throw JsonError("Trace ID was not provided for code event");
}
if (!span_id.isActive()) {
throw JsonError("Span ID was not provided for code event");
}
if (!message.isActive()) {
throw JsonError("Message was not provided for code event");
}
sdk_server->sendDebug(
file.get(),
func.get(),
line.get(),
getDebugLevel(),
trace_id.get(),
span_id.get(),
message.get(),
additional_fields.isActive() ? additional_fields.get() : map<string, string>()
);
return;
}
case SdkApiType::SendEventDrivenEvent: {
if (!event_name.isActive()) {
throw JsonError("Event name was not provided for event");
}
sdk_server->sendLog(
event_name.get(),
getAudience(),
getSeverity(),
getPriority(),
tag.get(),
additional_fields.isActive() ? additional_fields.get() : map<string, string>()
);
return;
}
case SdkApiType::SendGetConfigRequest: {
if (!config_path.isActive()) {
throw JsonError("Config path was not provided for get configuration event");
}
Maybe<string> config_val = sdk_server->getConfigValue(config_path.get());
config_value = config_val.ok() ? config_val.unpack() : "";
return;
}
case SdkApiType::SendPeriodicEvent: {
if (!event_name.isActive()) {
throw JsonError("Event name was not provided for periodic event");
}
if (!service_name.isActive()) {
throw JsonError("Service name was not provided for periodic event");
}
sdk_server->sendMetric(
event_name,
service_name,
getAudienceTeam(),
ReportIS::IssuingEngine::AGENT_CORE,
additional_fields.isActive() ? additional_fields.get() : map<string, string>()
);
return;
}
default: {
dbgError(D_EXTERNAL_SDK_SERVER) << "Received illegal event type. Type : " << event_type.get();
}
}
}
private:
static string
convertApiTypeToString(SdkApiType type)
{
static const EnumArray<SdkApiType, string> api_type_string {
"Code Event",
"Periodic Event",
"Event Driven",
"Get Configuration",
};
return api_type_string[type];
}
Debug::DebugLevel
getDebugLevel()
{
static const map<int, Debug::DebugLevel> debug_levels = {
{0, Debug::DebugLevel::TRACE},
{1, Debug::DebugLevel::DEBUG},
{2, Debug::DebugLevel::INFO},
{3, Debug::DebugLevel::WARNING},
{4, Debug::DebugLevel::ERROR}
};
if (!debug_level.isActive()) {
throw JsonError("Debug level was not provided for code event");
}
auto level = debug_levels.find(debug_level.get());
if(level == debug_levels.end()) {
throw JsonError("Illegal debug level provided");
}
return level->second;
}
ReportIS::Severity
getSeverity()
{
if (!severity.isActive()) {
throw JsonError("Event severity was not provided for periodic event");
}
switch (severity.get()) {
case EventSeverity::SeverityCritical: return ReportIS::Severity::CRITICAL;
case EventSeverity::SeverityHigh: return ReportIS::Severity::HIGH;
case EventSeverity::SeverityMedium: return ReportIS::Severity::MEDIUM;
case EventSeverity::SeverityLow: return ReportIS::Severity::LOW;
case EventSeverity::SeverityInfo: return ReportIS::Severity::INFO;
default:
throw JsonError("Illegal event severity provided");
}
}
ReportIS::Priority
getPriority()
{
if (!priority.isActive()) {
throw JsonError("Event priority was not provided");
}
switch (priority.get()) {
case EventPriority::PriorityUrgent: return ReportIS::Priority::URGENT;
case EventPriority::PriorityHigh: return ReportIS::Priority::HIGH;
case EventPriority::PriorityMedium: return ReportIS::Priority::MEDIUM;
case EventPriority::PriorityLow: return ReportIS::Priority::LOW;
default:
throw JsonError("Illegal event priority provided");
}
}
ReportIS::Audience
getAudience()
{
if (!audience.isActive()) {
throw JsonError("Event audience was not provided");
}
switch (audience.get()) {
case EventAudience::AudienceSecurity: return ReportIS::Audience::SECURITY;
case EventAudience::AudienceInternal: return ReportIS::Audience::INTERNAL;
default:
throw JsonError("Illegal event audience provided");
}
}
ReportIS::AudienceTeam
getAudienceTeam()
{
if (!team.isActive()) {
throw JsonError("Event audience team was not provided");
}
switch (team.get()) {
case EventAudienceTeam::AudienceTeamAgentCore: return ReportIS::AudienceTeam::AGENT_CORE;
case EventAudienceTeam::AudienceTeamIot: return ReportIS::AudienceTeam::IOT_NEXT;
case EventAudienceTeam::AudienceTeamWaap: return ReportIS::AudienceTeam::WAAP;
case EventAudienceTeam::AudienceTeamAgentIntelligence: return ReportIS::AudienceTeam::AGENT_INTELLIGENCE;
default:
throw JsonError("Illegal event audience team provided");
}
}
using additional_fields_map = map<string, string>;
C2S_LABEL_PARAM(int, event_type, "eventType");
C2S_LABEL_OPTIONAL_PARAM(additional_fields_map, additional_fields, "additionalFields");
C2S_LABEL_OPTIONAL_PARAM(string, event_name, "eventName");
C2S_LABEL_OPTIONAL_PARAM(string, service_name, "serviceName");
C2S_OPTIONAL_PARAM(int, team);
C2S_OPTIONAL_PARAM(int, audience);
C2S_OPTIONAL_PARAM(int, severity);
C2S_OPTIONAL_PARAM(int, priority);
C2S_OPTIONAL_PARAM(string, tag);
C2S_OPTIONAL_PARAM(string, file);
C2S_OPTIONAL_PARAM(string, func);
C2S_OPTIONAL_PARAM(int, line);
C2S_LABEL_OPTIONAL_PARAM(int, debug_level, "debugLevel");
C2S_LABEL_OPTIONAL_PARAM(string, trace_id, "traceId");
C2S_LABEL_OPTIONAL_PARAM(string, span_id, "spanId");
C2S_OPTIONAL_PARAM(string, message);
C2S_LABEL_OPTIONAL_PARAM(string, config_path, "configPath");
S2C_LABEL_OPTIONAL_PARAM(string, config_value, "configValue");
};
class ExternalSdkServer::Impl
:
public Singleton::Provide<I_ExternalSdkServer>::From<ExternalSdkServer>
{
public:
void
init()
{
auto rest = Singleton::Consume<I_RestApi>::by<ExternalSdkServer>();
rest->addRestCall<ExternalSdkRest>(RestAction::ADD, "sdk-call");
}
void
sendLog(
const string &event_name,
ReportIS::Audience audience,
ReportIS::Severity severity,
ReportIS::Priority priority,
const string &tag_string,
const map<string, string> &additional_fields)
{
Maybe<ReportIS::Tags> tag = TagAndEnumManagement::convertStringToTag(tag_string);
set<ReportIS::Tags> tags;
if (tag.ok()) tags.insert(tag.unpack());
LogGen log(event_name, audience, severity, priority, tags);
for (const auto &field : additional_fields) {
log << LogField(field.first, field.second);
}
}
void
sendDebug(
const string &file_name,
const string &function_name,
unsigned int line_number,
Debug::DebugLevel debug_level,
const string &trace_id,
const string &span_id,
const string &message,
const map<string, string> &additional_fields)
{
(void)trace_id;
(void)span_id;
Debug debug(file_name, function_name, line_number, debug_level, D_EXTERNAL_SDK_USER);
debug.getStreamAggr() << message;
bool is_first_key = true;
for (const auto &field : additional_fields) {
if (is_first_key) {
is_first_key = false;
debug.getStreamAggr() << ". ";
} else {
debug.getStreamAggr() << ", ";
}
debug.getStreamAggr() << "\"" << field.first << "\": \"" << field.second << "\"";
}
}
void
sendMetric(
const string &event_title,
const string &service_name,
ReportIS::AudienceTeam team,
ReportIS::IssuingEngine issuing_engine,
const map<string, string> &additional_fields)
{
ScopedContext ctx;
ctx.registerValue("Service Name", service_name);
set<ReportIS::Tags> tags;
Report metric_to_fog(
event_title,
Singleton::Consume<I_TimeGet>::by<GenericMetric>()->getWalltime(),
ReportIS::Type::PERIODIC,
ReportIS::Level::LOG,
ReportIS::LogLevel::INFO,
ReportIS::Audience::INTERNAL,
team,
ReportIS::Severity::INFO,
ReportIS::Priority::LOW,
chrono::seconds(0),
LogField("agentId", Singleton::Consume<I_AgentDetails>::by<GenericMetric>()->getAgentId()),
tags,
ReportIS::Tags::INFORMATIONAL,
issuing_engine
);
for (const auto &field : additional_fields) {
metric_to_fog << LogField(field.first, field.second);
}
LogRest metric_client_rest(metric_to_fog);
string fog_metric_uri = getConfigurationWithDefault<string>("/api/v1/agents/events", "metric", "fogMetricUri");
Singleton::Consume<I_Messaging>::by<ExternalSdkServer>()->sendAsyncMessage(
HTTPMethod::POST,
fog_metric_uri,
metric_client_rest,
MessageCategory::METRIC,
MessageMetadata(),
false
);
}
Maybe<string>
getConfigValue(const string &config_path)
{
auto config_val = getProfileAgentSetting<string>(config_path);
if (!config_val.ok()) {
stringstream error;
error << "Failed to get configuration. Config path: " << config_path << ", Error: " << config_val.getErr();
return genError(error.str());
}
return config_val.unpack();
}
};
ExternalSdkServer::ExternalSdkServer() : Component("ExternalSdkServer"), pimpl(make_unique<Impl>()) {}
ExternalSdkServer::~ExternalSdkServer() {}
void ExternalSdkServer::init() { pimpl->init(); }
void ExternalSdkServer::fini() {}
void ExternalSdkServer::preload() {}

View File

@@ -0,0 +1,7 @@
link_directories(${BOOST_ROOT}/lib)
add_unit_test(
external_sdk_server_ut
"external_sdk_server_ut.cc"
"external_sdk_server;mainloop;singleton;rest;environment;time_proxy;logging;event_is;metric;-lboost_context;agent_details;-lboost_regex;messaging;"
)

View File

@@ -0,0 +1,349 @@
#include <stdio.h>
#include <stdarg.h>
#include "external_sdk_server.h"
#include "cptest.h"
#include "mock/mock_rest_api.h"
#include "mock/mock_messaging.h"
#include "mock/mock_logging.h"
#include "mock/mock_time_get.h"
#include "config.h"
#include "config_component.h"
#include "agent_details.h"
using namespace std;
using namespace testing;
class ExternalSdkServerTest : public Test
{
public:
ExternalSdkServerTest()
{
EXPECT_CALL(rest_mocker, mockRestCall(RestAction::ADD, "sdk-call", _)).WillOnce(
WithArg<2>(
Invoke(
[this](const unique_ptr<RestInit> &rest_ptr)
{
mock_sdk_rest = rest_ptr->getRest();
return true;
}
)
)
);
sdk_server.preload();
sdk_server.init();
i_sdk = Singleton::Consume<I_ExternalSdkServer>::from(sdk_server);
}
~ExternalSdkServerTest()
{
sdk_server.fini();
}
ExternalSdkServer sdk_server;
NiceMock<MockTimeGet> mock_timer;
StrictMock<MockMessaging> messaging_mocker;
StrictMock<MockRestApi> rest_mocker;
StrictMock<MockLogging> log_mocker;
unique_ptr<ServerRest> mock_sdk_rest;
I_ExternalSdkServer *i_sdk;
ConfigComponent conf;
AgentDetails agent_details;
::Environment env;
};
TEST_F(ExternalSdkServerTest, initTest)
{
}
TEST_F(ExternalSdkServerTest, configCall)
{
Maybe<string> no_conf = i_sdk->getConfigValue("key1");
EXPECT_FALSE(no_conf.ok());
string config_json =
"{\n"
"\"agentSettings\": [\n"
"{\n"
"\"id\": \"id1\",\n"
"\"key\": \"key1\",\n"
"\"value\": \"value1\"\n"
"},\n"
"{\n"
"\"id\": \"id1\",\n"
"\"key\": \"key2\",\n"
"\"value\": \"value2\"\n"
"}\n"
"]\n"
"}\n";
conf.preload();
istringstream conf_stream(config_json);
ASSERT_TRUE(Singleton::Consume<Config::I_Config>::from(conf)->loadConfiguration(conf_stream));
Maybe<string> conf_found = i_sdk->getConfigValue("key1");
ASSERT_TRUE(conf_found.ok());
EXPECT_EQ(conf_found.unpack(), "value1");
conf_found = i_sdk->getConfigValue("key2");
ASSERT_TRUE(conf_found.ok());
EXPECT_EQ(conf_found.unpack(), "value2");
stringstream config_call_body;
config_call_body << "{ \"eventType\": 3, \"configPath\": \"key1\" }";
Maybe<string> sdk_conf = mock_sdk_rest->performRestCall(config_call_body);
ASSERT_TRUE(sdk_conf.ok());
EXPECT_EQ(
sdk_conf.unpack(),
"{\n"
" \"configValue\": \"value1\"\n"
"}"
);
}
template <typename T>
string
toJson(const T &obj)
{
stringstream ss;
{
cereal::JSONOutputArchive ar(ss);
obj.serialize(ar);
}
return ss.str();
}
TEST_F(ExternalSdkServerTest, eventDrivenCall)
{
string generated_log;
EXPECT_CALL(log_mocker, getCurrentLogId()).Times(2).WillRepeatedly(Return(0));
EXPECT_CALL(log_mocker, sendLog(_)).Times(2).WillRepeatedly(
WithArg<0>(
Invoke(
[&] (const Report &msg)
{
generated_log = toJson(msg);
}
)
)
);
i_sdk->sendLog(
"my log",
ReportIS::Audience::INTERNAL,
ReportIS::Severity::LOW,
ReportIS::Priority::HIGH,
"IPS",
{{"key1", "value1"}, {"key2", "value2"}}
);
static const string expected_log =
"{\n"
" \"eventTime\": \"\",\n"
" \"eventName\": \"my log\",\n"
" \"eventSeverity\": \"Low\",\n"
" \"eventPriority\": \"High\",\n"
" \"eventType\": \"Event Driven\",\n"
" \"eventLevel\": \"Log\",\n"
" \"eventLogLevel\": \"info\",\n"
" \"eventAudience\": \"Internal\",\n"
" \"eventAudienceTeam\": \"\",\n"
" \"eventFrequency\": 0,\n"
" \"eventTags\": [\n"
" \"IPS\"\n"
" ],\n"
" \"eventSource\": {\n"
" \"agentId\": \"Unknown\",\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
" \"serviceName\": \"Unnamed Nano Service\"\n"
" },\n"
" \"eventData\": {\n"
" \"logIndex\": 0,\n"
" \"key1\": \"value1\",\n"
" \"key2\": \"value2\"\n"
" }\n"
"}";
EXPECT_EQ(generated_log, expected_log);
string event_call_body =
"{\n"
" \"eventType\": 2,\n"
" \"eventName\": \"my log\",\n"
" \"audience\": 1,\n"
" \"severity\": 3,\n"
" \"priority\": 1,\n"
" \"tag\": \"IPS\",\n"
" \"team\": 3,\n"
" \"additionalFields\": {\n"
" \"key1\": \"value1\",\n"
" \"key2\": \"value2\"\n"
" }\n"
"}";
generated_log = "";
stringstream event_call_stream;
event_call_stream << event_call_body;
EXPECT_TRUE(mock_sdk_rest->performRestCall(event_call_stream).ok());
EXPECT_EQ(generated_log, expected_log);
}
TEST_F(ExternalSdkServerTest, periodicEventCall)
{
string message_body;
EXPECT_CALL(
messaging_mocker,
sendAsyncMessage(
HTTPMethod::POST,
"/api/v1/agents/events",
_,
MessageCategory::METRIC,
_,
false
)
).Times(2).WillRepeatedly(SaveArg<2>(&message_body));
i_sdk->sendMetric(
"my metric",
"matrix",
ReportIS::AudienceTeam::AGENT_INTELLIGENCE,
ReportIS::IssuingEngine::AGENT_CORE,
{{"key", "value"}}
);
static const string expected_message =
"{\n"
" \"log\": {\n"
" \"eventTime\": \"\",\n"
" \"eventName\": \"my metric\",\n"
" \"eventSeverity\": \"Info\",\n"
" \"eventPriority\": \"Low\",\n"
" \"eventType\": \"Periodic\",\n"
" \"eventLevel\": \"Log\",\n"
" \"eventLogLevel\": \"info\",\n"
" \"eventAudience\": \"Internal\",\n"
" \"eventAudienceTeam\": \"Agent Intelligence\",\n"
" \"eventFrequency\": 0,\n"
" \"eventTags\": [\n"
" \"Informational\"\n"
" ],\n"
" \"eventSource\": {\n"
" \"agentId\": \"Unknown\",\n"
" \"issuingEngine\": \"Agent Core\",\n"
" \"eventTraceId\": \"\",\n"
" \"eventSpanId\": \"\",\n"
" \"issuingEngineVersion\": \"\",\n"
" \"serviceName\": \"matrix\"\n"
" },\n"
" \"eventData\": {\n"
" \"key\": \"value\"\n"
" }\n"
" }\n"
"}";
EXPECT_EQ(message_body, expected_message);
string event_call_body =
"{\n"
" \"eventType\": 1,\n"
" \"eventName\": \"my metric\",\n"
" \"serviceName\": \"matrix\",\n"
" \"team\": 3,\n"
" \"additionalFields\": {\n"
" \"key\": \"value\"\n"
" }\n"
"}";
stringstream event_call_stream;
event_call_stream << event_call_body;
message_body = "";
EXPECT_TRUE(mock_sdk_rest->performRestCall(event_call_stream).ok());
EXPECT_EQ(message_body, expected_message);
}
USE_DEBUG_FLAG(D_EXTERNAL_SDK_USER);
USE_DEBUG_FLAG(D_EXTERNAL_SDK_SERVER);
TEST_F(ExternalSdkServerTest, codeEventCall)
{
ostringstream capture_debug;
Debug::setUnitTestFlag(D_EXTERNAL_SDK_SERVER, Debug::DebugLevel::TRACE);
Debug::setUnitTestFlag(D_EXTERNAL_SDK_USER, Debug::DebugLevel::TRACE);
Debug::setNewDefaultStdout(&capture_debug);
i_sdk->sendDebug(
"file.cc",
"myFunc2",
42,
Debug::DebugLevel::TRACE,
"123",
"abc",
"h#l1ow w0r!d",
{{"hi", "universe"}}
);
EXPECT_THAT(
capture_debug.str(),
HasSubstr(
"[myFunc2@file.cc:42 | >>>] "
"h#l1ow w0r!d. \"hi\": \"universe\"\n"
)
);
string debug_event =
"{\n"
" \"eventType\": 0,\n"
" \"file\": \"my file\",\n"
" \"func\": \"function_name\",\n"
" \"line\": 42,\n"
" \"debugLevel\": 0,\n"
" \"traceId\": \"\",\n"
" \"spanId\": \"span2323\",\n"
" \"message\": \"some short debug\",\n"
" \"team\": 1,\n"
" \"additionalFields\": {\n"
" \"name\": \"moshe\",\n"
" \"food\": \"bamba\"\n"
" }\n"
"}";
stringstream event_call_stream;
event_call_stream << debug_event;
EXPECT_TRUE(mock_sdk_rest->performRestCall(event_call_stream).ok());
EXPECT_THAT(
capture_debug.str(),
HasSubstr(
"[function_name@my file:42 | >>>] "
"some short debug. \"food\": \"bamba\", \"name\": \"moshe\"\n"
)
);
Debug::setNewDefaultStdout(&cout);
}
TEST_F(ExternalSdkServerTest, ilegalEventCall)
{
string event_call_body =
"{\n"
" \"eventType\": 7,\n"
" \"eventName\": \"my metric\",\n"
" \"serviceName\": \"matrix\",\n"
" \"team\": 3,\n"
" \"additionalFields\": {\n"
" \"key\": \"value\"\n"
" }\n"
"}";
stringstream event_call_stream;
event_call_stream << event_call_body;
Maybe<string> failed_respond = mock_sdk_rest->performRestCall(event_call_stream);
EXPECT_FALSE(failed_respond.ok());
EXPECT_EQ(failed_respond.getErr(), "Illegal event type provided");
}

View File

@@ -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();

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