mirror of
https://github.com/openappsec/openappsec.git
synced 2025-12-31 13:49:08 +03:00
First release of open-appsec source code
This commit is contained in:
14
components/CMakeLists.txt
Normal file
14
components/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
add_subdirectory(report_messaging)
|
||||
add_subdirectory(http_manager)
|
||||
add_subdirectory(http_transaction_data)
|
||||
add_subdirectory(generic_rulebase)
|
||||
add_subdirectory(signal_handler)
|
||||
add_subdirectory(gradual_deployment)
|
||||
add_subdirectory(packet)
|
||||
add_subdirectory(pending_key)
|
||||
add_subdirectory(messaging_downloader)
|
||||
add_subdirectory(health_check_manager)
|
||||
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(attachment-intakers)
|
||||
add_subdirectory(security_apps)
|
||||
2
components/attachment-intakers/CMakeLists.txt
Normal file
2
components/attachment-intakers/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
add_subdirectory(nginx_attachment)
|
||||
add_subdirectory(attachment_registrator)
|
||||
1
components/attachment-intakers/attachment_registrator/CMakeLists.txt
Executable file
1
components/attachment-intakers/attachment_registrator/CMakeLists.txt
Executable file
@@ -0,0 +1 @@
|
||||
add_library(attachment_registrator attachment_registrator.cc)
|
||||
470
components/attachment-intakers/attachment_registrator/attachment_registrator.cc
Executable file
470
components/attachment-intakers/attachment_registrator/attachment_registrator.cc
Executable file
@@ -0,0 +1,470 @@
|
||||
// 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 "attachment_registrator.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/un.h>
|
||||
#include <climits>
|
||||
#include <unordered_map>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "singleton.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "buffer.h"
|
||||
#include "enum_array.h"
|
||||
#include "nginx_attachment_common.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_ATTACHMENT_REGISTRATION);
|
||||
|
||||
using namespace std;
|
||||
|
||||
class AttachmentRegistrator::Impl
|
||||
{
|
||||
public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
i_socket = Singleton::Consume<I_Socket>::by<AttachmentRegistrator>();
|
||||
Singleton::Consume<I_MainLoop>::by<AttachmentRegistrator>()->addOneTimeRoutine(
|
||||
I_MainLoop::RoutineType::System,
|
||||
[this] ()
|
||||
{
|
||||
while(!initSocket()) {
|
||||
Singleton::Consume<I_MainLoop>::by<AttachmentRegistrator>()->yield(chrono::seconds(1));
|
||||
}
|
||||
},
|
||||
"Initialize attachment registration IPC"
|
||||
);
|
||||
|
||||
uint expiration_timeout = getProfileAgentSettingWithDefault<uint>(
|
||||
300, "attachmentRegistrator.expirationCheckSeconds"
|
||||
);
|
||||
Singleton::Consume<I_MainLoop>::by<AttachmentRegistrator>()->addRecurringRoutine(
|
||||
I_MainLoop::RoutineType::Timer,
|
||||
chrono::seconds(expiration_timeout),
|
||||
[this] () { handleExpiration(); },
|
||||
"Attachment's expiration handler",
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
fini()
|
||||
{
|
||||
if (server_sock > 0) {
|
||||
i_socket->closeSocket(server_sock);
|
||||
server_sock = -1;
|
||||
}
|
||||
|
||||
if (shared_registration_path != "") unlink(shared_registration_path.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
bool
|
||||
registerAttachmentProcess(
|
||||
const uint8_t &uid,
|
||||
const string &family_id,
|
||||
const uint8_t num_of_members,
|
||||
const AttachmentType type)
|
||||
{
|
||||
registered_attachments[family_id] = vector<bool>(num_of_members, true);
|
||||
|
||||
const int cmd_tmout = 900;
|
||||
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<AttachmentRegistrator>();
|
||||
Maybe<string> registration_res = shell_cmd->getExecOutput(
|
||||
genRegCommand(family_id, num_of_members, type),
|
||||
cmd_tmout
|
||||
);
|
||||
if (!registration_res.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Failed to register attachment."
|
||||
<< "Attachment Type: "
|
||||
<< static_cast<int>(type)
|
||||
<< ", Attachment id: "
|
||||
<< uid
|
||||
<<", Family id: "
|
||||
<< family_id
|
||||
<< ", Total number of instances: "
|
||||
<< num_of_members;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
replyWithRelevantHandler(
|
||||
I_Socket::socketFd socket,
|
||||
const uint8_t &uid,
|
||||
const string &family_id,
|
||||
const AttachmentType type)
|
||||
{
|
||||
string handler_path = genHandlerPath(uid, family_id, type);
|
||||
|
||||
uint8_t path_size = handler_path.size();
|
||||
vector<char> path_size_data(reinterpret_cast<char *>(&path_size), reinterpret_cast<char *>(&path_size) + 1);
|
||||
if (!i_socket->writeData(socket, path_size_data)) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION) << "Failed to send handler path size to attachment";
|
||||
return;
|
||||
}
|
||||
|
||||
dbgDebug(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Successfully sent handler path size to attachment. Size: "
|
||||
<< to_string(path_size);
|
||||
|
||||
vector<char> path_data(handler_path.data(), handler_path.data() + handler_path.size());
|
||||
if (!i_socket->writeData(socket, path_data)) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Failed to send handler path data to attachment. Path: "
|
||||
<< handler_path;
|
||||
return;
|
||||
}
|
||||
|
||||
dbgDebug(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Successfully sent handler path data to attachment. Path: "
|
||||
<< handler_path;
|
||||
}
|
||||
|
||||
string
|
||||
genHandlerPath(const uint8_t &uid, const string &family_id, const AttachmentType type) const
|
||||
{
|
||||
static const string handler_path_format = "/dev/shm/check-point/cp-nano-";
|
||||
stringstream handler_path;
|
||||
handler_path << handler_path_format;
|
||||
switch(type) {
|
||||
case (AttachmentType::NGINX_ATT_ID): {
|
||||
handler_path << "http-transaction-handler-";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dbgAssert(false) << "Unsupported Attachment " << static_cast<int>(type);
|
||||
}
|
||||
|
||||
if (!family_id.empty()) handler_path << family_id << "_";
|
||||
handler_path << to_string(uid);
|
||||
|
||||
return handler_path.str();
|
||||
}
|
||||
|
||||
string
|
||||
genRegCommand(const string &family_id, const uint num_of_members, const AttachmentType type) const
|
||||
{
|
||||
dbgAssert(num_of_members > 0) << "Failed to generate a registration command for an empty group of attachments";
|
||||
|
||||
static const string registration_format = "/etc/cp/watchdog/cp-nano-watchdog --register ";
|
||||
stringstream registration_command;
|
||||
registration_command<< registration_format;
|
||||
switch(type) {
|
||||
case (AttachmentType::NGINX_ATT_ID): {
|
||||
registration_command << "/etc/cp/HttpTransactionHandler/cp-nano-http-transaction-handler";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dbgAssert(false) << "Unsupported Attachment " << static_cast<int>(type);
|
||||
}
|
||||
|
||||
if (!family_id.empty()) registration_command << " --family " << family_id;
|
||||
registration_command << " --count " << to_string(num_of_members);
|
||||
|
||||
return registration_command.str();
|
||||
}
|
||||
|
||||
bool
|
||||
initSocket()
|
||||
{
|
||||
shared_registration_path = getConfigurationWithDefault<string>(
|
||||
"/dev/shm/check-point/cp-nano-attachment-registration",
|
||||
"Attachment Registration",
|
||||
"Registration IPC Path"
|
||||
);
|
||||
|
||||
size_t last_slash_idx = shared_registration_path.find_last_of("/");
|
||||
string directory_path = shared_registration_path.substr(0, last_slash_idx);
|
||||
mkdir(directory_path.c_str(), 0777);
|
||||
|
||||
if (server_sock < 0) {
|
||||
server_sock = getNewSocket(shared_registration_path);
|
||||
if (server_sock < 0) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Failed to create server socket. Path: "
|
||||
<< shared_registration_path;
|
||||
return false;
|
||||
}
|
||||
|
||||
Singleton::Consume<I_MainLoop>::by<AttachmentRegistrator>()->addFileRoutine(
|
||||
I_MainLoop::RoutineType::RealTime,
|
||||
server_sock,
|
||||
[this] () { handleAttachmentRegistration(); },
|
||||
"Attachment's registration handler",
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
string shared_expiration_path = getConfigurationWithDefault<string>(
|
||||
SHARED_KEEP_ALIVE_PATH,
|
||||
"Attachment Registration",
|
||||
"Registration IPC Path"
|
||||
);
|
||||
|
||||
if (keep_alive_sock < 0) {
|
||||
keep_alive_sock = getNewSocket(shared_expiration_path);
|
||||
if (keep_alive_sock < 0) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION) << "Failed to create keep-alive socket";
|
||||
return false;
|
||||
}
|
||||
|
||||
Singleton::Consume<I_MainLoop>::by<AttachmentRegistrator>()->addFileRoutine(
|
||||
I_MainLoop::RoutineType::System,
|
||||
keep_alive_sock,
|
||||
[this] () { handleKeepAlives(); },
|
||||
"Attachment keep alive registration",
|
||||
true
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
I_Socket::socketFd
|
||||
getNewSocket(const string &path)
|
||||
{
|
||||
Maybe<I_Socket::socketFd> new_socket = i_socket->genSocket(
|
||||
I_Socket::SocketType::UNIX,
|
||||
false,
|
||||
true,
|
||||
path
|
||||
);
|
||||
if (!new_socket.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION) << "Failed to open a socket. Error: " << new_socket.getErr();
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbgAssert(new_socket.unpack() > 0) << "Generated socket is OK yet negative";
|
||||
return new_socket.unpack();
|
||||
}
|
||||
|
||||
void
|
||||
handleKeepAlives()
|
||||
{
|
||||
Maybe<I_Socket::socketFd> accepted_socket = i_socket->acceptSocket(keep_alive_sock, false);
|
||||
if (!accepted_socket.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Failed to accept new keep-alive request socket: "
|
||||
<< accepted_socket.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
I_Socket::socketFd client_socket = accepted_socket.unpack();
|
||||
dbgAssert(client_socket > 0) << "Generated client socket is OK yet negative";
|
||||
auto close_socket_on_exit = make_scope_exit([&]() { i_socket->closeSocket(client_socket); });
|
||||
|
||||
Maybe<uint8_t> attachment_id = readNumericParam(client_socket);
|
||||
if (!attachment_id.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION) << "Failed to register new attachment: " << attachment_id.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<string> family_id = readStringParam(client_socket);
|
||||
if (!family_id.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION) << "Failed to register new attachment: " << family_id.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
if (family_id.unpack() == "") return;
|
||||
|
||||
auto family_members = registered_attachments.find(family_id.unpack());
|
||||
if (family_members == registered_attachments.end()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Adding new unregistered family. Family ID: "
|
||||
<< family_id.unpack();
|
||||
registered_attachments[family_id.unpack()] = vector<bool>(attachment_id.unpack() + 1, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (family_members->second.size() <= attachment_id.unpack()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Adding new non-monitored family members. Family ID: "
|
||||
<< family_id.unpack()
|
||||
<< ", Instance ID:"
|
||||
<< attachment_id.unpack();
|
||||
|
||||
registered_attachments[family_id.unpack()] = vector<bool>(attachment_id.unpack() + 1, true);
|
||||
return;
|
||||
}
|
||||
family_members->second[attachment_id.unpack()] = true;
|
||||
}
|
||||
|
||||
void
|
||||
handleExpiration()
|
||||
{
|
||||
I_ShellCmd *shell_cmd = Singleton::Consume<I_ShellCmd>::by<AttachmentRegistrator>();
|
||||
vector<string> deleted_families;
|
||||
for (pair<const string, vector<bool, allocator<bool>>> &family : registered_attachments) {
|
||||
const string &family_id = family.first;
|
||||
if (family_id == "") continue;
|
||||
|
||||
bool is_family_inactive = true;
|
||||
vector<bool> &family_members = family.second;
|
||||
for (const bool member : family_members) {
|
||||
if (member == true) is_family_inactive = false;
|
||||
}
|
||||
|
||||
if (is_family_inactive) {
|
||||
static const string unregister_format = "/etc/cp/watchdog/cp-nano-watchdog --un-register ";
|
||||
stringstream unregister_command;
|
||||
unregister_command << unregister_format;
|
||||
unregister_command << "/etc/cp/HttpTransactionHandler/cp-nano-http-transaction-handler";
|
||||
unregister_command << " --family " << family_id;
|
||||
|
||||
Maybe<string> res = shell_cmd->getExecOutput(unregister_command.str());
|
||||
if (!res.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Failed to un-register attachment. Family id: "
|
||||
<< family_id;
|
||||
} else {
|
||||
deleted_families.push_back(family_id);
|
||||
}
|
||||
} else {
|
||||
fill(family_members.begin(), family_members.end(), false);
|
||||
}
|
||||
}
|
||||
|
||||
for (const string &family : deleted_families) {
|
||||
registered_attachments.erase(family);
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Successfully un-registered attachments family. Family id: "
|
||||
<< family;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handleAttachmentRegistration()
|
||||
{
|
||||
Maybe<I_Socket::socketFd> accepted_socket = i_socket->acceptSocket(server_sock, false);
|
||||
if (!accepted_socket.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Failed to accept a new client socket: "
|
||||
<< accepted_socket.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
I_Socket::socketFd client_socket = accepted_socket.unpack();
|
||||
dbgAssert(client_socket > 0) << "Generated client socket is OK yet negative";
|
||||
auto close_socket_on_exit = make_scope_exit([&]() { i_socket->closeSocket(client_socket); });
|
||||
|
||||
Maybe<AttachmentType> attachment_type = readAttachmentType(client_socket);
|
||||
if (!attachment_type.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Failed to register a new attachment: "
|
||||
<< attachment_type.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<uint8_t> attachment_id = readNumericParam(client_socket);
|
||||
if (!attachment_id.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION) << "Failed to register a new attachment: " << attachment_id.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<uint8_t> instances_count = readNumericParam(client_socket);
|
||||
if (!instances_count.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Failed to register a new attachment: "
|
||||
<< instances_count.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<string> family_id = readStringParam(client_socket);
|
||||
if (!family_id.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION) << "Failed to register a new attachment: " << family_id.getErr();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!registerAttachmentProcess(*attachment_id, *family_id, *instances_count, *attachment_type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
replyWithRelevantHandler(client_socket, *attachment_id, *family_id, *attachment_type);
|
||||
}
|
||||
|
||||
Maybe<uint8_t>
|
||||
readNumericParam(I_Socket::socketFd socket)
|
||||
{
|
||||
Maybe<vector<char>> param_to_read = i_socket->receiveData(socket, sizeof(uint8_t));
|
||||
if (!param_to_read.ok()) {
|
||||
dbgWarning(D_ATTACHMENT_REGISTRATION) << "Failed to read param: " << param_to_read.getErr();
|
||||
return genError("Failed to read numeric parameter");
|
||||
}
|
||||
|
||||
return *reinterpret_cast<const uint8_t *>(param_to_read.unpack().data());
|
||||
}
|
||||
|
||||
Maybe<AttachmentType>
|
||||
readAttachmentType(I_Socket::socketFd socket)
|
||||
{
|
||||
Maybe<uint8_t> attachment_type = readNumericParam(socket);
|
||||
if (!attachment_type.ok()) return attachment_type.passErr();
|
||||
|
||||
dbgTrace(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Successfully received attachment type. Attachment type value: "
|
||||
<< static_cast<int>(*attachment_type);
|
||||
|
||||
return convertToEnum<AttachmentType>(*attachment_type);
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
readStringParam(I_Socket::socketFd socket)
|
||||
{
|
||||
Maybe<uint8_t> param_size = readNumericParam(socket);
|
||||
if (!param_size.ok()) return param_size.passErr();
|
||||
|
||||
dbgTrace(D_ATTACHMENT_REGISTRATION)
|
||||
<< "Successfully received string size. Size: "
|
||||
<< static_cast<int>(*param_size);
|
||||
|
||||
Maybe<vector<char>> param_to_read = i_socket->receiveData(socket, param_size.unpack());
|
||||
|
||||
return string(param_to_read.unpack().begin(), param_to_read.unpack().end());
|
||||
}
|
||||
|
||||
I_Socket::socketFd server_sock = -1;
|
||||
I_Socket::socketFd keep_alive_sock = -1;
|
||||
I_Socket *i_socket = nullptr;
|
||||
map<string, vector<bool>> registered_attachments;
|
||||
string shared_registration_path;
|
||||
};
|
||||
|
||||
AttachmentRegistrator::AttachmentRegistrator() : Component("AttachmentRegistrator"), pimpl(make_unique<Impl>()) {}
|
||||
|
||||
AttachmentRegistrator::~AttachmentRegistrator() {}
|
||||
|
||||
void AttachmentRegistrator::init() { pimpl->init(); }
|
||||
|
||||
void AttachmentRegistrator::fini() { pimpl->fini(); }
|
||||
|
||||
void
|
||||
AttachmentRegistrator::preload()
|
||||
{
|
||||
registerExpectedConfiguration<string>("Attachment Registration", "Registration IPC Path");
|
||||
}
|
||||
5
components/attachment-intakers/nginx_attachment/CMakeLists.txt
Executable file
5
components/attachment-intakers/nginx_attachment/CMakeLists.txt
Executable file
@@ -0,0 +1,5 @@
|
||||
add_definitions(-DUSERSPACE)
|
||||
|
||||
add_library(nginx_attachment nginx_attachment.cc nginx_attachment_config.cc nginx_attachment_opaque.cc nginx_parser.cc user_identifiers_config.cc nginx_intaker_metric.cc nginx_attachment_metric.cc cidrs_data.cc)
|
||||
|
||||
target_link_libraries(nginx_attachment http_configuration http_transaction_data connkey table buffers -lshmem_ipc)
|
||||
128
components/attachment-intakers/nginx_attachment/cidrs_data.cc
Executable file
128
components/attachment-intakers/nginx_attachment/cidrs_data.cc
Executable file
@@ -0,0 +1,128 @@
|
||||
#include "cidrs_data.h"
|
||||
|
||||
#include "log_generator.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_ATTACHMENT_PARSER);
|
||||
|
||||
|
||||
bool
|
||||
CIDRSData::matchCidr(const in_addr &address, const in_addr &network) const
|
||||
{
|
||||
if (network_bits == 0) {
|
||||
// C99 6.5.7 (3): u32 << 32 is undefined behaviour
|
||||
return true;
|
||||
}
|
||||
return !((address.s_addr ^ network.s_addr) & htonl(0xFFFFFFFFu << (32 - network_bits)));
|
||||
}
|
||||
|
||||
bool
|
||||
CIDRSData::matchCidr(const in6_addr &address, const in6_addr &network) const
|
||||
{
|
||||
#ifdef __linux__
|
||||
const uint32_t *a = address.s6_addr32;
|
||||
const uint32_t *n = network.s6_addr32;
|
||||
#else
|
||||
const uint32_t *a = address.__u6_addr.__u6_addr32;
|
||||
const uint32_t *n = network.__u6_addr.__u6_addr32;
|
||||
#endif
|
||||
int bits_whole, bits_incomplete;
|
||||
bits_whole = network_bits >> 5; // number of whole u32
|
||||
bits_incomplete = network_bits & 0x1F; // number of bits in incomplete u32
|
||||
if (bits_whole) {
|
||||
if (memcmp(a, n, bits_whole << 2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (bits_incomplete) {
|
||||
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
|
||||
if ((a[bits_whole] ^ n[bits_whole]) & mask) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CIDRSData::CIDRSData(const string &str_cidr)
|
||||
{
|
||||
size_t processed_bits = 0;
|
||||
|
||||
size_t pos = str_cidr.find_last_of('/');
|
||||
|
||||
// get ip from targetCidr
|
||||
string str_prefix = pos != string::npos ? str_cidr.substr(0, pos) : str_cidr;
|
||||
// get subnet mask from targetCidr or calculate it based on ipv4 / ipv6
|
||||
string str_suffix;
|
||||
if (pos != string::npos) {
|
||||
str_suffix = str_cidr.substr(pos + 1);
|
||||
} else if (str_cidr.find(':') == string::npos) {
|
||||
str_suffix = "32";
|
||||
} else {
|
||||
str_suffix = "128";
|
||||
}
|
||||
|
||||
|
||||
int bits = -1;
|
||||
try {
|
||||
bits = stoi(str_suffix, &processed_bits);
|
||||
network_bits = (uint8_t)bits;
|
||||
// convert int to uint8_t
|
||||
} catch (...) {
|
||||
dbgWarning(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Failed to convert CIDR number of bits from string to int"
|
||||
<< str_cidr;
|
||||
return;
|
||||
}
|
||||
|
||||
// check if CIDR is valid
|
||||
if (processed_bits != str_suffix.length() || bits > 128 || bits < 0) {
|
||||
dbgWarning(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Failed to convert CIDR number of bits from string to int (out of range)."
|
||||
<< str_cidr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IPAddr::isValidIPAddr(str_prefix)) {
|
||||
ip_addr = IPAddr::createIPAddr(str_prefix).unpack();
|
||||
} else {
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Failed to convert CIDR number of bits from string to int";
|
||||
return;
|
||||
}
|
||||
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "successfully created cidr from the following string: " << str_cidr;
|
||||
valid_cidr = true;
|
||||
}
|
||||
|
||||
bool
|
||||
CIDRSData::contains(const string &source_ip) const
|
||||
{
|
||||
if(!valid_cidr) {
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Invalid CIDR.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// check from which type the target ip and check if ip belongs to is mask ip
|
||||
//convert source_ip to ip v4 or v6.
|
||||
switch (ip_addr.getType()) {
|
||||
case IPType::V4: {
|
||||
struct in_addr source_inaddr;
|
||||
if (inet_pton(AF_INET, source_ip.c_str(), &source_inaddr) == 1) {
|
||||
return matchCidr(source_inaddr, ip_addr.getIPv4());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPType::V6: {
|
||||
struct in6_addr source_inaddr6;
|
||||
if (inet_pton(AF_INET6, source_ip.c_str(), &source_inaddr6) == 1) {
|
||||
return matchCidr(source_inaddr6, ip_addr.getIPv6());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
dbgWarning(D_NGINX_ATTACHMENT_PARSER) << "Unexpected ip type";
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
28
components/attachment-intakers/nginx_attachment/cidrs_data.h
Executable file
28
components/attachment-intakers/nginx_attachment/cidrs_data.h
Executable file
@@ -0,0 +1,28 @@
|
||||
#ifndef __CIDRS_DATA_H__
|
||||
#define __CIDRS_DATA_H__
|
||||
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include "maybe_res.h"
|
||||
#include "connkey.h"
|
||||
|
||||
class CIDRSData
|
||||
{
|
||||
public:
|
||||
CIDRSData(const std::string &str_cidr);
|
||||
bool contains(const std::string &source_ip) const;
|
||||
|
||||
private:
|
||||
bool matchCidr(const in_addr &address, const in_addr &net) const;
|
||||
bool matchCidr(const in6_addr &address, const in6_addr &network) const;
|
||||
|
||||
IPAddr ip_addr;
|
||||
uint8_t network_bits;
|
||||
bool valid_cidr = false;
|
||||
};
|
||||
|
||||
#endif // __CIDRS_DATA_H__
|
||||
145
components/attachment-intakers/nginx_attachment/intentional_failure.cc
Executable file
145
components/attachment-intakers/nginx_attachment/intentional_failure.cc
Executable file
@@ -0,0 +1,145 @@
|
||||
// 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 "intentional_failure.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <unistd.h>
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_ATTACHMENT);
|
||||
|
||||
IntentionalFailureHandler::FailureType
|
||||
getFailureTypeFromString(const string &failure)
|
||||
{
|
||||
if (failure == "create socket") return IntentionalFailureHandler::FailureType::CreateSocket;
|
||||
if (failure == "accept socket") return IntentionalFailureHandler::FailureType::AcceptSocket;
|
||||
if (failure == "initialize connection channel")
|
||||
return IntentionalFailureHandler::FailureType::InitializeConnectionChannel;
|
||||
if (failure == "write to socket") return IntentionalFailureHandler::FailureType::WriteDataToSocket;
|
||||
if (failure == "read from socket") return IntentionalFailureHandler::FailureType::ReceiveDataFromSocket;
|
||||
if (failure == "parse response") return IntentionalFailureHandler::FailureType::ParsingResponse;
|
||||
if (failure == "get data from attachment") return IntentionalFailureHandler::FailureType::GetDataFromAttchment;
|
||||
if (failure == "register attachment") return IntentionalFailureHandler::FailureType::RegisterAttchment;
|
||||
if (failure == "get instance id") return IntentionalFailureHandler::FailureType::GetInstanceID;
|
||||
|
||||
if (failure != "") {
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Ignoring unknown intentional failure type:" << failure;
|
||||
}
|
||||
return IntentionalFailureHandler::FailureType::None;
|
||||
}
|
||||
|
||||
void
|
||||
IntentionalFailureHandler::RegisterIntentionalFailure()
|
||||
{
|
||||
is_failure_enabled = getConfigurationWithDefault<bool>(
|
||||
false, "HTTP manager", "Enable intentional failure mode"
|
||||
);
|
||||
|
||||
string failure_type_str = getConfigurationWithDefault<string>("", "HTTP manager", "Intentional failure type");
|
||||
failure_type = getFailureTypeFromString(failure_type_str);
|
||||
if (failure_type == FailureType::None) is_failure_enabled = false;
|
||||
|
||||
allow_count = getConfigurationWithDefault<int>(0, "HTTP manager", "Intentional failure allow times");
|
||||
fail_count = getConfigurationWithDefault<int>(-1, "HTTP manager", "Intentional failure limit");
|
||||
is_limited = fail_count > 0;
|
||||
|
||||
is_delay_enabled = getConfigurationWithDefault<bool>(
|
||||
false, "HTTP manager", "Enable intentional delay mode"
|
||||
);
|
||||
|
||||
string delay_failure_type_str = getConfigurationWithDefault<string>(
|
||||
"", "HTTP manager", "Intentional delay failure type"
|
||||
);
|
||||
delay_failure_type = getFailureTypeFromString(delay_failure_type_str);
|
||||
|
||||
delay_amount = chrono::microseconds(
|
||||
getConfigurationWithDefault<int>(-1, "HTTP manager", "Intentional delay amount")
|
||||
);
|
||||
|
||||
if (delay_failure_type == FailureType::None || delay_amount <= chrono::microseconds(0)) is_delay_enabled = false;
|
||||
|
||||
if (is_failure_enabled) {
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Registered Intentional failure. Type: " << failure_type_str
|
||||
<< ", will allow first " << to_string(allow_count) << " actions"
|
||||
<< ", fail limit: " << (is_limited ? to_string(fail_count) : "unlimited");
|
||||
}
|
||||
|
||||
if (is_delay_enabled) {
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Registered Intentional delay. Type: " << delay_failure_type_str
|
||||
<< ", amount: " << delay_amount.count() << " microseconds";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
IntentionalFailureHandler::init()
|
||||
{
|
||||
RegisterIntentionalFailure();
|
||||
registerConfigLoadCb([this]() { RegisterIntentionalFailure(); });
|
||||
if (!is_failure_enabled && !is_delay_enabled) {
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Initialized Intentional failure. No failure/delay was specified";
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
IntentionalFailureHandler::shouldFail(
|
||||
bool was_originaly_successful,
|
||||
IntentionalFailureHandler::FailureType failure,
|
||||
bool *failed_on_purpose
|
||||
)
|
||||
{
|
||||
*failed_on_purpose = false;
|
||||
if (is_failure_enabled && failure_type == failure) {
|
||||
if (allow_count > 0) {
|
||||
allow_count --;
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Intentional failure: allowed action, remaining tries to be allowed: "
|
||||
<< to_string(allow_count);
|
||||
return !was_originaly_successful;
|
||||
}
|
||||
if (is_limited) {
|
||||
if (fail_count <= 0) return !was_originaly_successful;
|
||||
fail_count --;
|
||||
}
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Intentional failure was activated, remaining failures: "
|
||||
<< (is_limited ? to_string(fail_count) : "unlimited");
|
||||
*failed_on_purpose = true;
|
||||
return true;
|
||||
}
|
||||
return !was_originaly_successful;
|
||||
}
|
||||
|
||||
void
|
||||
IntentionalFailureHandler::delayIfNeeded(IntentionalFailureHandler::FailureType failure)
|
||||
{
|
||||
if (is_delay_enabled && delay_failure_type == failure) {
|
||||
dbgInfo(D_NGINX_ATTACHMENT) << "Intentional delay was activated (" << delay_amount.count() << " microseconds)";
|
||||
usleep(delay_amount.count());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IntentionalFailureHandler::preload()
|
||||
{
|
||||
registerExpectedConfiguration<bool>("HTTP manager", "Enable intentional failure mode");
|
||||
registerExpectedConfiguration<string>("HTTP manager", "Intentional failure type");
|
||||
registerExpectedConfiguration<int>("HTTP manager", "Intentional failure limit");
|
||||
registerExpectedConfiguration<int>("HTTP manager", "Intentional failure allow times");
|
||||
registerExpectedConfiguration<bool>("HTTP manager", "Enable intentional delay mode");
|
||||
registerExpectedConfiguration<string>("HTTP manager", "Intentional delay failure type");
|
||||
registerExpectedConfiguration<int>("HTTP manager", "Intentional delay amount");
|
||||
}
|
||||
56
components/attachment-intakers/nginx_attachment/intentional_failure.h
Executable file
56
components/attachment-intakers/nginx_attachment/intentional_failure.h
Executable file
@@ -0,0 +1,56 @@
|
||||
// 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 __INTENTIONAL_FAILURE__
|
||||
#define __INTENTIONAL_FAILURE__
|
||||
|
||||
#include <chrono>
|
||||
|
||||
class IntentionalFailureHandler
|
||||
{
|
||||
public:
|
||||
enum class FailureType {
|
||||
None,
|
||||
CreateSocket,
|
||||
AcceptSocket,
|
||||
InitializeConnectionChannel,
|
||||
WriteDataToSocket,
|
||||
ReceiveDataFromSocket,
|
||||
ParsingResponse,
|
||||
GetDataFromAttchment,
|
||||
RegisterAttchment,
|
||||
GetInstanceID,
|
||||
COUNT
|
||||
};
|
||||
|
||||
void init();
|
||||
bool shouldFail(bool was_originaly_successful, FailureType failure, bool *failed_on_purpose);
|
||||
void delayIfNeeded(FailureType failure);
|
||||
|
||||
void preload();
|
||||
|
||||
private:
|
||||
void RegisterIntentionalFailure();
|
||||
|
||||
FailureType failure_type;
|
||||
bool is_failure_enabled;
|
||||
bool is_limited;
|
||||
int fail_count;
|
||||
int allow_count;
|
||||
|
||||
FailureType delay_failure_type;
|
||||
bool is_delay_enabled;
|
||||
std::chrono::microseconds delay_amount;
|
||||
};
|
||||
|
||||
#endif // __INTENTIONAL_FAILURE__
|
||||
1785
components/attachment-intakers/nginx_attachment/nginx_attachment.cc
Executable file
1785
components/attachment-intakers/nginx_attachment/nginx_attachment.cc
Executable file
File diff suppressed because it is too large
Load Diff
331
components/attachment-intakers/nginx_attachment/nginx_attachment_config.cc
Executable file
331
components/attachment-intakers/nginx_attachment/nginx_attachment_config.cc
Executable file
@@ -0,0 +1,331 @@
|
||||
// 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 "nginx_attachment_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nginx_attachment.h"
|
||||
#include "config.h"
|
||||
#include "singleton.h"
|
||||
#include "i_gradual_deployment.h"
|
||||
#include "debug.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_ATTACHMENT);
|
||||
|
||||
using namespace std;
|
||||
|
||||
using DebugLevel = ngx_http_cp_debug_level_e;
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::init()
|
||||
{
|
||||
setDebugLevel();
|
||||
setGradualDeploymentIPs();
|
||||
setWebTriggerConf();
|
||||
setStaticResourcesPath();
|
||||
setFailOpenMode();
|
||||
setFailOpenTimeout();
|
||||
setFailOpenWaitMode();
|
||||
setSessionsPerMinuteLimitVerdict();
|
||||
setMaxSessionsPerMinute();
|
||||
setNumOfNginxIpcElements();
|
||||
setDebugByContextValues();
|
||||
setKeepAliveIntervalMsec();
|
||||
}
|
||||
|
||||
bool
|
||||
HttpAttachmentConfig::operator==(const HttpAttachmentConfig &other) const
|
||||
{
|
||||
return
|
||||
web_trigger_conf == other.web_trigger_conf &&
|
||||
conf_data == other.conf_data;
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::save(cereal::JSONOutputArchive &out_ar) const
|
||||
{
|
||||
conf_data.save(out_ar);
|
||||
}
|
||||
|
||||
template <typename Conf, typename ...Strings>
|
||||
static Conf
|
||||
getAttachmentConf(const Conf &default_val, const string &profile_conf, const Strings & ...conf)
|
||||
{
|
||||
const Conf &profile_settings = getProfileAgentSettingWithDefault<Conf>(default_val, profile_conf);
|
||||
return getConfigurationWithDefault<Conf>(profile_settings, conf...);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setGradualDeploymentIPs()
|
||||
{
|
||||
auto i_gradual_deployment = Singleton::Consume<I_GradualDeployment>::by<NginxAttachment>();
|
||||
conf_data.setExcludeSources(i_gradual_deployment->getPolicy(I_GradualDeployment::AttachmentType::NGINX));
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setWebTriggerConf()
|
||||
{
|
||||
web_trigger_conf = getConfigurationWithDefault<WebTriggerConf>(
|
||||
WebTriggerConf::default_trigger_conf,
|
||||
"HTTP manager",
|
||||
"Web trigger conf"
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setDebugLevel() {
|
||||
string debug_level = getAttachmentConf<string>(
|
||||
"info",
|
||||
"agent.debug.flag.nginxModule",
|
||||
"HTTP manager",
|
||||
"Attachment debug level"
|
||||
);
|
||||
|
||||
debug_level[0] = toupper(debug_level[0]);
|
||||
|
||||
if (debug_level == "Trace") {
|
||||
conf_data.setNumericalValue("dbg_level", (unsigned int)DebugLevel::DBG_LEVEL_TRACE);
|
||||
} else if (debug_level == "Debug") {
|
||||
conf_data.setNumericalValue("dbg_level", (unsigned int)DebugLevel::DBG_LEVEL_DEBUG);
|
||||
} else if (debug_level == "Info") {
|
||||
conf_data.setNumericalValue("dbg_level", (unsigned int)DebugLevel::DBG_LEVEL_INFO);
|
||||
} else if (debug_level == "Warning") {
|
||||
conf_data.setNumericalValue("dbg_level", (unsigned int)DebugLevel::DBG_LEVEL_WARNING);
|
||||
} else if (debug_level == "Error") {
|
||||
conf_data.setNumericalValue("dbg_level", (unsigned int)DebugLevel::DBG_LEVEL_ERROR);
|
||||
} else {
|
||||
dbgWarning(D_NGINX_ATTACHMENT)
|
||||
<< "Debug level \""
|
||||
<< debug_level
|
||||
<< "\" is not valid. using default level \"warning\"";
|
||||
conf_data.setNumericalValue("dbg_level", (unsigned int)DebugLevel::DBG_LEVEL_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setFailOpenMode()
|
||||
{
|
||||
bool is_fail_open_mode_enabled = getAttachmentConf<bool>(
|
||||
true,
|
||||
"agent.failOpenState.nginxModule",
|
||||
"HTTP manager",
|
||||
"Fail Open Mode state"
|
||||
);
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "Attachment failure mode is: "
|
||||
<< (is_fail_open_mode_enabled ? "Enabled" : "Disabled");
|
||||
conf_data.setNumericalValue("is_fail_open_mode_enabled", is_fail_open_mode_enabled);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setFailOpenTimeout()
|
||||
{
|
||||
conf_data.setNumericalValue("fail_open_timeout", getAttachmentConf<uint>(
|
||||
50,
|
||||
"agent.failOpenTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"Fail Open timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("fail_open_hold_timeout", getAttachmentConf<uint>(
|
||||
150,
|
||||
"agent.failOpenWaitTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"Fail Open wait timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("res_proccessing_timeout_msec", getAttachmentConf<uint>(
|
||||
3000,
|
||||
"agent.resProccessingTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX response processing timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("req_proccessing_timeout_msec", getAttachmentConf<uint>(
|
||||
3000,
|
||||
"agent.reqProccessingTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX request processing timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("registration_thread_timeout_msec", getAttachmentConf<uint>(
|
||||
100,
|
||||
"agent.registrationThreadTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX registration thread timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("req_header_thread_timeout_msec", getAttachmentConf<uint>(
|
||||
100,
|
||||
"agent.reqHeaderThreadTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX request header thread timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("req_body_thread_timeout_msec", getAttachmentConf<uint>(
|
||||
150,
|
||||
"agent.reqBodyThreadTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX request body thread timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("res_header_thread_timeout_msec", getAttachmentConf<uint>(
|
||||
100,
|
||||
"agent.resHeaderThreadTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX response header thread timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("res_body_thread_timeout_msec", getAttachmentConf<uint>(
|
||||
150,
|
||||
"agent.resBodyThreadTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX response body thread timeout msec"
|
||||
));
|
||||
|
||||
conf_data.setNumericalValue("waiting_for_verdict_thread_timeout_msec", getAttachmentConf<uint>(
|
||||
150,
|
||||
"agent.waitThreadTimeout.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX wait thread timeout msec"
|
||||
));
|
||||
|
||||
uint inspection_mode = getAttachmentConf<uint>(
|
||||
static_cast<uint>(ngx_http_inspection_mode_e::NON_BLOCKING_THREAD),
|
||||
"agent.inspectionMode.nginxModule",
|
||||
"HTTP manager",
|
||||
"NGINX inspection mode"
|
||||
);
|
||||
|
||||
if (inspection_mode >= ngx_http_inspection_mode_e::INSPECTION_MODE_COUNT) {
|
||||
inspection_mode = ngx_http_inspection_mode_e::NON_BLOCKING_THREAD;
|
||||
}
|
||||
conf_data.setNumericalValue("nginx_inspection_mode", inspection_mode);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setFailOpenWaitMode()
|
||||
{
|
||||
bool is_fail_open_mode_hold_enabled = getAttachmentConf<bool>(
|
||||
true,
|
||||
"agent.failOpenWaitState.nginxModule",
|
||||
"HTTP manager",
|
||||
"Fail Open Mode state"
|
||||
);
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "Attachment waiting failure mode is: "
|
||||
<< (is_fail_open_mode_hold_enabled ? "Enabled" : "Disabled");
|
||||
conf_data.setNumericalValue("is_fail_open_mode_hold_enabled", is_fail_open_mode_hold_enabled);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setSessionsPerMinuteLimitVerdict()
|
||||
{
|
||||
string sessions_per_minute_limit_verdict = getAttachmentConf<string>(
|
||||
"Accept",
|
||||
"agent.sessionsPerMinuteLimitVerdict.nginxModule",
|
||||
"HTTP manager",
|
||||
"Sessions Per Minute Limit Verdict"
|
||||
);
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "Attachment sessions per minute limit verdict is: "
|
||||
<< sessions_per_minute_limit_verdict;
|
||||
|
||||
conf_data.setStringValue("sessions_per_minute_limit_verdict", sessions_per_minute_limit_verdict);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setMaxSessionsPerMinute()
|
||||
{
|
||||
uint max_sessions_per_minute = getAttachmentConf<uint>(
|
||||
0,
|
||||
"agent.maxSessionsPerMinute.nginxModule",
|
||||
"HTTP manager",
|
||||
"Max Sessions Per Minute"
|
||||
);
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "Attachment max sessions per minute is: "
|
||||
<< max_sessions_per_minute;
|
||||
|
||||
conf_data.setNumericalValue("max_sessions_per_minute", max_sessions_per_minute);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setNumOfNginxIpcElements()
|
||||
{
|
||||
uint num_of_nginx_ipc_elements = getProfileAgentSettingWithDefault<uint>(
|
||||
NUM_OF_NGINX_IPC_ELEMENTS, "nginxAttachment.numOfNginxIpcElements"
|
||||
);
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "Number of NGINX IPC elements: "
|
||||
<< num_of_nginx_ipc_elements;
|
||||
conf_data.setNumericalValue("num_of_nginx_ipc_elements", num_of_nginx_ipc_elements);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setKeepAliveIntervalMsec()
|
||||
{
|
||||
uint keep_alive_interval_msec = getProfileAgentSettingWithDefault<uint>(
|
||||
300, "attachmentRegistrator.expirationCheckSeconds"
|
||||
);
|
||||
keep_alive_interval_msec = (keep_alive_interval_msec * 1000) / 2;
|
||||
dbgDebug(D_NGINX_ATTACHMENT)
|
||||
<< "Interval keeps alives size: "
|
||||
<< keep_alive_interval_msec << " msec";
|
||||
conf_data.setNumericalValue("keep_alive_interval_msec", keep_alive_interval_msec);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setStaticResourcesPath()
|
||||
{
|
||||
string static_resources_path = getConfigurationWithDefault<string>(
|
||||
DEFAULT_STATIC_RESOURCES_PATH,
|
||||
"HTTP manager",
|
||||
"Static resources path"
|
||||
);
|
||||
dbgDebug(D_NGINX_ATTACHMENT) << "Static resources path is : " << static_resources_path;
|
||||
conf_data.setStringValue("static_resources_path", static_resources_path);
|
||||
}
|
||||
|
||||
void
|
||||
HttpAttachmentConfig::setDebugByContextValues()
|
||||
{
|
||||
DebugConfig new_ctx_cfg;
|
||||
auto maybe_ctx_config = getSetting<DebugConfig>("HTTP manager", "debug context");
|
||||
if(!maybe_ctx_config.ok()) {
|
||||
dbgDebug(D_NGINX_ATTACHMENT) << "Failed to set context values. Setting default values";
|
||||
conf_data.setDebugContext(new_ctx_cfg);
|
||||
return;
|
||||
}
|
||||
new_ctx_cfg = maybe_ctx_config.unpack();
|
||||
conf_data.setDebugContext(new_ctx_cfg);
|
||||
dbgDebug(D_NGINX_ATTACHMENT)
|
||||
<< "Setting context values : "
|
||||
<< "client_ip: "
|
||||
<< new_ctx_cfg.client
|
||||
<< ", listening_ip: "
|
||||
<< new_ctx_cfg.server
|
||||
<< ", uri_prefix: "
|
||||
<< new_ctx_cfg.uri
|
||||
<< ", hostname: "
|
||||
<< new_ctx_cfg.host
|
||||
<< ", http_method: "
|
||||
<< new_ctx_cfg.method
|
||||
<< ", listening_port: "
|
||||
<< new_ctx_cfg.port;
|
||||
}
|
||||
77
components/attachment-intakers/nginx_attachment/nginx_attachment_config.h
Executable file
77
components/attachment-intakers/nginx_attachment/nginx_attachment_config.h
Executable file
@@ -0,0 +1,77 @@
|
||||
// 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 __NGINX_ATTACHMENT_CONFIG_H__
|
||||
#define __NGINX_ATTACHMENT_CONFIG_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "nginx_attachment_util.h"
|
||||
#include "cereal/archives/json.hpp"
|
||||
|
||||
#include "generic_rulebase/triggers_config.h"
|
||||
#include "http_configuration.h"
|
||||
|
||||
class HttpAttachmentConfig
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
|
||||
bool operator==(const HttpAttachmentConfig &other) const;
|
||||
|
||||
void save(cereal::JSONOutputArchive &out_ar) const;
|
||||
|
||||
unsigned int getDebugLevel() const { return conf_data.getNumericalValue("dbg_level"); }
|
||||
bool getIsFailOpenModeEnabled() const { return conf_data.getNumericalValue("is_fail_open_mode_enabled"); }
|
||||
|
||||
bool
|
||||
getSessionsPerMinuteLimitVerdict() const
|
||||
{
|
||||
return conf_data.getNumericalValue("sessions_per_minute_limit_verdict");
|
||||
}
|
||||
|
||||
unsigned int getMaxSessionsPerMinute() const { return conf_data.getNumericalValue("max_sessions_per_minute"); }
|
||||
unsigned int getNumOfNginxElements() const { return conf_data.getNumericalValue("num_of_nginx_ipc_elements"); }
|
||||
unsigned int getKeepAliveIntervalMsec() const { return conf_data.getNumericalValue("keep_alive_interval_msec"); }
|
||||
|
||||
private:
|
||||
void setGradualDeploymentIPs();
|
||||
|
||||
void setWebTriggerConf();
|
||||
|
||||
void setDebugLevel();
|
||||
|
||||
void setFailOpenMode();
|
||||
|
||||
void setFailOpenTimeout();
|
||||
|
||||
void setFailOpenWaitMode();
|
||||
|
||||
void setSessionsPerMinuteLimitVerdict();
|
||||
|
||||
void setMaxSessionsPerMinute();
|
||||
|
||||
void setNumOfNginxIpcElements();
|
||||
|
||||
void setKeepAliveIntervalMsec();
|
||||
|
||||
void setStaticResourcesPath();
|
||||
|
||||
void setDebugByContextValues();
|
||||
|
||||
WebTriggerConf web_trigger_conf;
|
||||
HttpAttachmentConfiguration conf_data;
|
||||
};
|
||||
|
||||
#endif // __NGINX_ATTACHMENT_CONFIG_H__
|
||||
163
components/attachment-intakers/nginx_attachment/nginx_attachment_metric.cc
Executable file
163
components/attachment-intakers/nginx_attachment/nginx_attachment_metric.cc
Executable file
@@ -0,0 +1,163 @@
|
||||
// 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 "nginx_attachment_metric.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_METRICS_NGINX_ATTACHMENT);
|
||||
|
||||
void
|
||||
nginxAttachmentEvent::resetAllCounters()
|
||||
{
|
||||
successfull_registrations_counter = 0;
|
||||
failed_registrations_counter = 0;
|
||||
failed_connections_counter = 0;
|
||||
accept_verdict_counter = 0;
|
||||
inspect_verdict_counter = 0;
|
||||
drop_verdict_counter = 0;
|
||||
inject_verdict_counter = 0;
|
||||
irrelevant_verdict_counter = 0;
|
||||
reconf_verdict_counter = 0;
|
||||
wait_verdict_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
nginxAttachmentEvent::addNetworkingCounter(networkVerdict _verdict)
|
||||
{
|
||||
switch (_verdict) {
|
||||
case networkVerdict::REGISTRATION_SUCCESS: {
|
||||
successfull_registrations_counter += 1;
|
||||
break;
|
||||
}
|
||||
case networkVerdict::REGISTRATION_FAIL: {
|
||||
failed_registrations_counter += 1;
|
||||
break;
|
||||
}
|
||||
case networkVerdict::CONNECTION_FAIL: {
|
||||
failed_connections_counter += 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dbgWarning(D_METRICS_NGINX_ATTACHMENT) << "Unsupported metric type. Type: " << static_cast<int>(_verdict);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nginxAttachmentEvent::addTrafficVerdictCounter(trafficVerdict _verdict)
|
||||
{
|
||||
switch (_verdict) {
|
||||
case trafficVerdict::INSPECT: {
|
||||
inspect_verdict_counter += 1;
|
||||
break;
|
||||
}
|
||||
case trafficVerdict::ACCEPT: {
|
||||
accept_verdict_counter += 1;
|
||||
break;
|
||||
}
|
||||
case trafficVerdict::DROP: {
|
||||
drop_verdict_counter += 1;
|
||||
break;
|
||||
}
|
||||
case trafficVerdict::INJECT: {
|
||||
inject_verdict_counter += 1;
|
||||
break;
|
||||
}
|
||||
case trafficVerdict::IRRELEVANT: {
|
||||
irrelevant_verdict_counter += 1;
|
||||
break;
|
||||
}
|
||||
case trafficVerdict::RECONF: {
|
||||
reconf_verdict_counter += 1;
|
||||
break;
|
||||
}
|
||||
case trafficVerdict::WAIT: {
|
||||
wait_verdict_counter += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
dbgWarning(D_METRICS_NGINX_ATTACHMENT) << "Unsupported metric type. Type: " << static_cast<int>(_verdict);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nginxAttachmentEvent::addResponseInspectionCounter(uint64_t _counter)
|
||||
{
|
||||
response_inspection_counter += _counter;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nginxAttachmentEvent::getNetworkingCounter(networkVerdict _verdict) const
|
||||
{
|
||||
switch (_verdict) {
|
||||
case networkVerdict::REGISTRATION_SUCCESS:
|
||||
return successfull_registrations_counter;
|
||||
case networkVerdict::REGISTRATION_FAIL:
|
||||
return failed_registrations_counter;
|
||||
case networkVerdict::CONNECTION_FAIL:
|
||||
return failed_connections_counter;
|
||||
default:
|
||||
dbgWarning(D_METRICS_NGINX_ATTACHMENT) << "Unsupported metric type. Type: " << static_cast<int>(_verdict);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nginxAttachmentEvent::getTrafficVerdictCounter(trafficVerdict _verdict) const
|
||||
{
|
||||
switch (_verdict) {
|
||||
case trafficVerdict::INSPECT:
|
||||
return inspect_verdict_counter;
|
||||
case trafficVerdict::ACCEPT:
|
||||
return accept_verdict_counter;
|
||||
case trafficVerdict::DROP:
|
||||
return drop_verdict_counter;
|
||||
case trafficVerdict::INJECT:
|
||||
return inject_verdict_counter;
|
||||
case trafficVerdict::IRRELEVANT:
|
||||
return irrelevant_verdict_counter;
|
||||
case trafficVerdict::RECONF:
|
||||
return reconf_verdict_counter;
|
||||
case trafficVerdict::WAIT:
|
||||
return wait_verdict_counter;
|
||||
default:
|
||||
dbgWarning(D_METRICS_NGINX_ATTACHMENT) << "Unsupported metric type. Type: " << static_cast<int>(_verdict);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nginxAttachmentEvent::getResponseInspectionCounter() const
|
||||
{
|
||||
return response_inspection_counter;
|
||||
}
|
||||
|
||||
void
|
||||
nginxAttachmentMetric::upon(const nginxAttachmentEvent &event)
|
||||
{
|
||||
successfull_registrations.report(
|
||||
event.getNetworkingCounter(nginxAttachmentEvent::networkVerdict::REGISTRATION_SUCCESS)
|
||||
);
|
||||
failed_registrations.report(
|
||||
event.getNetworkingCounter(nginxAttachmentEvent::networkVerdict::REGISTRATION_FAIL)
|
||||
);
|
||||
failed_connections.report(event.getNetworkingCounter(nginxAttachmentEvent::networkVerdict::CONNECTION_FAIL));
|
||||
inspect_verdict.report(event.getTrafficVerdictCounter(nginxAttachmentEvent::trafficVerdict::INSPECT));
|
||||
accept_verdict.report(event.getTrafficVerdictCounter(nginxAttachmentEvent::trafficVerdict::ACCEPT));
|
||||
drop_verdict.report(event.getTrafficVerdictCounter(nginxAttachmentEvent::trafficVerdict::DROP));
|
||||
inject_verdict.report(event.getTrafficVerdictCounter(nginxAttachmentEvent::trafficVerdict::INJECT));
|
||||
irrelevant_verdict.report(event.getTrafficVerdictCounter(nginxAttachmentEvent::trafficVerdict::IRRELEVANT));
|
||||
reconf_verdict.report(event.getTrafficVerdictCounter(nginxAttachmentEvent::trafficVerdict::RECONF));
|
||||
response_inspection.report(event.getResponseInspectionCounter());
|
||||
}
|
||||
121
components/attachment-intakers/nginx_attachment/nginx_attachment_opaque.cc
Executable file
121
components/attachment-intakers/nginx_attachment/nginx_attachment_opaque.cc
Executable file
@@ -0,0 +1,121 @@
|
||||
// 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 "nginx_attachment_opaque.h"
|
||||
|
||||
#include "boost/uuid/uuid.hpp"
|
||||
#include "boost/uuid/uuid_generators.hpp"
|
||||
#include "boost/uuid/uuid_io.hpp"
|
||||
|
||||
#include "config.h"
|
||||
#include "sasal.h"
|
||||
#include "virtual_modifiers.h"
|
||||
|
||||
SASAL_START // HTTP Manager - Transaction data
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::uuids;
|
||||
|
||||
USE_DEBUG_FLAG(D_HTTP_MANAGER);
|
||||
|
||||
NginxAttachmentOpaque::NginxAttachmentOpaque(HttpTransactionData _transaction_data)
|
||||
:
|
||||
TableOpaqueSerialize<NginxAttachmentOpaque>(this),
|
||||
transaction_data(move(_transaction_data)),
|
||||
ctx(),
|
||||
session_tenant(),
|
||||
uuid()
|
||||
{
|
||||
try {
|
||||
uuid = to_string(boost::uuids::random_generator()());
|
||||
} catch (const boost::uuids::entropy_error &e) {
|
||||
dbgWarning(D_HTTP_MANAGER) << "Failed to generate UUID. Error: " << e.what();
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_MANAGER) << "Creating nginx opaque environment from: " << transaction_data;
|
||||
|
||||
response_compression_stream = initCompressionStream();
|
||||
|
||||
auto client_ip = transaction_data.getSourceIP();
|
||||
std::stringstream client_ip_str;
|
||||
client_ip_str << client_ip;
|
||||
setSourceIdentifier("sourceip", client_ip_str.str());
|
||||
|
||||
ctx.registerValue("eventReferenceId", uuid, EnvKeyAttr::LogSection::DATA);
|
||||
ctx.registerValue<string>(HttpTransactionData::http_proto_ctx, transaction_data.getHttpProtocol());
|
||||
ctx.registerValue<string>(HttpTransactionData::method_ctx, transaction_data.getHttpMethod());
|
||||
ctx.registerValue<string>(HttpTransactionData::host_name_ctx, transaction_data.getDestinationHost());
|
||||
ctx.registerValue<uint16_t>(HttpTransactionData::listening_port_ctx, transaction_data.getListeningPort());
|
||||
ctx.registerValue<IPAddr>(HttpTransactionData::listening_ip_ctx, transaction_data.getListeningIP());
|
||||
ctx.registerValue<IPAddr>(HttpTransactionData::client_ip_ctx, transaction_data.getSourceIP());
|
||||
ctx.registerValue<uint16_t>(HttpTransactionData::client_port_ctx, transaction_data.getSourcePort());
|
||||
ctx.registerFunc<string>(HttpTransactionData::source_identifier, [this](){ return source_identifier; });
|
||||
|
||||
ctx.registerValue<string>(HttpTransactionData::uri_ctx, transaction_data.getURI());
|
||||
auto decoder = makeVirtualContainer<HexDecoder<'%'>>(transaction_data.getURI());
|
||||
string decoded_url(decoder.begin(), decoder.end());
|
||||
auto question_mark_location = decoded_url.find('?');
|
||||
if (question_mark_location != string::npos) {
|
||||
ctx.registerValue(HttpTransactionData::uri_query_decoded, decoded_url.substr(question_mark_location + 1));
|
||||
}
|
||||
ctx.registerValue(HttpTransactionData::uri_path_decoded, decoded_url.substr(0, question_mark_location));
|
||||
}
|
||||
|
||||
NginxAttachmentOpaque::~NginxAttachmentOpaque()
|
||||
{
|
||||
finiCompressionStream(response_compression_stream);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START - sync functions, can only be tested once the sync module exists
|
||||
std::unique_ptr<TableOpaqueBase>
|
||||
NginxAttachmentOpaque::prototype()
|
||||
{
|
||||
return make_unique<NginxAttachmentOpaque>(HttpTransactionData());
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
NginxAttachmentOpaque::setSessionTenant(const string &tenant)
|
||||
{
|
||||
session_tenant = tenant;
|
||||
Singleton::Consume<I_Environment>::by<NginxAttachmentOpaque>()->setActiveTenant(session_tenant);
|
||||
}
|
||||
|
||||
void
|
||||
NginxAttachmentOpaque::setSourceIdentifier(const string &header_key, const string &new_source_identifier)
|
||||
{
|
||||
identifier_type = header_key;
|
||||
source_identifier = new_source_identifier;
|
||||
}
|
||||
|
||||
const string &
|
||||
NginxAttachmentOpaque::getSourceIdentifiersType() const
|
||||
{
|
||||
return identifier_type;
|
||||
}
|
||||
|
||||
void
|
||||
NginxAttachmentOpaque::addToSavedData(const string &name, const string &data)
|
||||
{
|
||||
saved_data[name] += data;
|
||||
ctx.registerValue(name, saved_data[name]);
|
||||
}
|
||||
|
||||
void
|
||||
NginxAttachmentOpaque::setSavedData(const string &name, const string &data, EnvKeyAttr::LogSection log_ctx)
|
||||
{
|
||||
saved_data[name] = data;
|
||||
ctx.registerValue(name, data, log_ctx);
|
||||
}
|
||||
|
||||
SASAL_END
|
||||
94
components/attachment-intakers/nginx_attachment/nginx_attachment_opaque.h
Executable file
94
components/attachment-intakers/nginx_attachment/nginx_attachment_opaque.h
Executable file
@@ -0,0 +1,94 @@
|
||||
// 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 __NGINX_ATTACHMENT_OPAQUE_H__
|
||||
#define __NGINX_ATTACHMENT_OPAQUE_H__
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include "compression_utils.h"
|
||||
#include "generic_rulebase/generic_rulebase_context.h"
|
||||
#include "http_transaction_data.h"
|
||||
#include "table_opaque.h"
|
||||
#include "context.h"
|
||||
#include "i_environment.h"
|
||||
#include "buffer.h"
|
||||
|
||||
class NginxAttachmentOpaque : public TableOpaqueSerialize<NginxAttachmentOpaque>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
NginxAttachmentOpaque(HttpTransactionData transaction_data);
|
||||
~NginxAttachmentOpaque();
|
||||
|
||||
void
|
||||
activateContext()
|
||||
{
|
||||
ctx.activate();
|
||||
gen_ctx.activate();
|
||||
if (session_tenant != "") {
|
||||
Singleton::Consume<I_Environment>::by<NginxAttachmentOpaque>()->setActiveTenant(session_tenant);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
deactivateContext()
|
||||
{
|
||||
if (session_tenant != "") {
|
||||
Singleton::Consume<I_Environment>::by<NginxAttachmentOpaque>()->unsetActiveTenant();
|
||||
}
|
||||
gen_ctx.deactivate();
|
||||
ctx.deactivate();
|
||||
}
|
||||
|
||||
CompressionStream * getResponseCompressionStream() { return response_compression_stream; }
|
||||
HttpTransactionData & getTransactionData() { return transaction_data; }
|
||||
|
||||
// LCOV_EXCL_START - sync functions, can only be tested once the sync module exists
|
||||
template <typename T> void serialize(T &, uint) {}
|
||||
static std::unique_ptr<TableOpaqueBase> prototype();
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
static const std::string name() { return "NginxAttachmentOpaque"; }
|
||||
static uint currVer() { return 0; }
|
||||
static uint minVer() { return 0; }
|
||||
|
||||
const std::string & getSessionTenant() const { return session_tenant; }
|
||||
void setSessionTenant(const std::string &tenant);
|
||||
void setSourceIdentifier(const std::string &header_key, const std::string &source_identifier);
|
||||
const std::string & getSourceIdentifiersType() const;
|
||||
|
||||
const std::string & getSessionUUID() const { return uuid; }
|
||||
|
||||
void addToSavedData(const std::string &name, const std::string &data);
|
||||
void setSavedData(
|
||||
const std::string &name,
|
||||
const std::string &data,
|
||||
EnvKeyAttr::LogSection log_ctx = EnvKeyAttr::LogSection::NONE
|
||||
);
|
||||
|
||||
private:
|
||||
CompressionStream *response_compression_stream;
|
||||
HttpTransactionData transaction_data;
|
||||
GenericRulebaseContext gen_ctx;
|
||||
Context ctx;
|
||||
std::string session_tenant;
|
||||
std::string uuid;
|
||||
std::string source_identifier;
|
||||
std::string identifier_type;
|
||||
std::map<std::string, std::string> saved_data;
|
||||
};
|
||||
|
||||
#endif // __NGINX_ATTACHMENT_OPAQUE_H__
|
||||
502
components/attachment-intakers/nginx_attachment/nginx_intaker_metric.cc
Executable file
502
components/attachment-intakers/nginx_attachment/nginx_intaker_metric.cc
Executable file
@@ -0,0 +1,502 @@
|
||||
// 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 "nginx_intaker_metric.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_METRICS_NGINX_ATTACHMENT);
|
||||
|
||||
void
|
||||
nginxIntakerEvent::resetAllCounters()
|
||||
{
|
||||
successfull_inspection_counter = 0;
|
||||
open_failure_inspection_counter = 0;
|
||||
close_failure_inspection_counter = 0;
|
||||
transparent_mode_counter = 0;
|
||||
total_transparent_time = 0;
|
||||
accept_verdict_counter = 0;
|
||||
inspect_verdict_counter = 0;
|
||||
drop_verdict_counter = 0;
|
||||
inject_verdict_counter = 0;
|
||||
irrelevant_verdict_counter = 0;
|
||||
reconf_verdict_counter = 0;
|
||||
wait_verdict_counter = 0;
|
||||
req_failed_compression_counter = 0;
|
||||
res_failed_compression_counter = 0;
|
||||
req_failed_decompression_counter = 0;
|
||||
res_failed_decompression_counter = 0;
|
||||
req_successful_compression_counter = 0;
|
||||
res_successful_compression_counter = 0;
|
||||
req_successful_decompression_counter = 0;
|
||||
res_successful_decompression_counter = 0;
|
||||
corrupted_zip_skipped_session_counter = 0;
|
||||
thread_timeout = 0;
|
||||
reg_thread_timeout = 0;
|
||||
req_header_thread_timeout = 0;
|
||||
req_body_thread_timeout = 0;
|
||||
res_header_thread_timeout = 0;
|
||||
res_body_thread_timeout = 0;
|
||||
thread_failure = 0;
|
||||
req_proccessing_timeout = 0;
|
||||
res_proccessing_timeout = 0;
|
||||
req_failed_to_reach_upstream = 0;
|
||||
cpu_event.setCPU(0);
|
||||
}
|
||||
|
||||
ngx_http_plugin_metric_type_e
|
||||
nginxIntakerEvent::EnumOfIndex(int i)
|
||||
{
|
||||
return static_cast<ngx_http_plugin_metric_type_e>(i);
|
||||
}
|
||||
|
||||
void
|
||||
nginxIntakerEvent::addPluginMetricCounter(const ngx_http_cp_metric_data_t *recieved_metric_data)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(ngx_http_plugin_metric_type_e::METRIC_TYPES_COUNT); i++) {
|
||||
ngx_http_plugin_metric_type_e metric_type = EnumOfIndex(i);
|
||||
uint64_t amount = recieved_metric_data->data[i];
|
||||
switch (metric_type) {
|
||||
case ngx_http_plugin_metric_type_e::INSPECTION_SUCCESSES_COUNT: {
|
||||
successfull_inspection_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::INSPECTION_OPEN_FAILURES_COUNT: {
|
||||
open_failure_inspection_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::INSPECTION_CLOSE_FAILURES_COUNT: {
|
||||
close_failure_inspection_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::TRANSPARENTS_COUNT: {
|
||||
transparent_mode_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::TOTAL_TRANSPARENTS_TIME: {
|
||||
total_transparent_time += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::INSPECT_VERDICTS_COUNT: {
|
||||
inspect_verdict_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::ACCEPT_VERDICTS_COUNT: {
|
||||
accept_verdict_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::DROP_VERDICTS_COUNT: {
|
||||
drop_verdict_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::INJECT_VERDICTS_COUNT: {
|
||||
inject_verdict_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::IRRELEVANT_VERDICTS_COUNT: {
|
||||
irrelevant_verdict_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::RECONF_VERDICTS_COUNT: {
|
||||
reconf_verdict_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) average_overall_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MAX_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) max_overall_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MIN_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) min_overall_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_REQ_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) average_req_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MAX_REQ_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) max_req_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MIN_REQ_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) min_req_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) average_res_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) max_res_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT: {
|
||||
if (amount > 0) min_res_processing_time_until_verdict = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REQ_FAILED_COMPRESSION_COUNT: {
|
||||
req_failed_compression_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::RES_FAILED_COMPRESSION_COUNT: {
|
||||
res_failed_compression_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REQ_FAILED_DECOMPRESSION_COUNT: {
|
||||
req_failed_decompression_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::RES_FAILED_DECOMPRESSION_COUNT: {
|
||||
res_failed_decompression_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REQ_SUCCESSFUL_COMPRESSION_COUNT: {
|
||||
req_successful_compression_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::RES_SUCCESSFUL_COMPRESSION_COUNT: {
|
||||
res_successful_compression_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REQ_SUCCESSFUL_DECOMPRESSION_COUNT: {
|
||||
req_successful_decompression_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::RES_SUCCESSFUL_DECOMPRESSION_COUNT: {
|
||||
res_successful_decompression_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::CORRUPTED_ZIP_SKIPPED_SESSION_COUNT: {
|
||||
corrupted_zip_skipped_session_counter += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::THREAD_TIMEOUT: {
|
||||
thread_timeout += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REG_THREAD_TIMEOUT: {
|
||||
reg_thread_timeout += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REQ_HEADER_THREAD_TIMEOUT: {
|
||||
req_header_thread_timeout += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REQ_BODY_THREAD_TIMEOUT: {
|
||||
req_body_thread_timeout += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_REQ_BODY_SIZE_UPON_TIMEOUT: {
|
||||
if (amount > 0) average_req_body_size_upon_timeout = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MAX_REQ_BODY_SIZE_UPON_TIMEOUT: {
|
||||
if (amount > 0) max_req_body_size_upon_timeout = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MIN_REQ_BODY_SIZE_UPON_TIMEOUT: {
|
||||
if (amount > 0) min_req_body_size_upon_timeout = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::RES_HEADER_THREAD_TIMEOUT: {
|
||||
res_header_thread_timeout += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::RES_BODY_THREAD_TIMEOUT: {
|
||||
res_body_thread_timeout += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_RES_BODY_SIZE_UPON_TIMEOUT: {
|
||||
if (amount > 0) average_res_body_size_upon_timeout = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MAX_RES_BODY_SIZE_UPON_TIMEOUT: {
|
||||
if (amount > 0) max_res_body_size_upon_timeout = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::MIN_RES_BODY_SIZE_UPON_TIMEOUT: {
|
||||
if (amount > 0) min_res_body_size_upon_timeout = amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::THREAD_FAILURE: {
|
||||
thread_failure += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REQ_PROCCESSING_TIMEOUT: {
|
||||
req_proccessing_timeout += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::RES_PROCCESSING_TIMEOUT: {
|
||||
res_proccessing_timeout += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::REQ_FAILED_TO_REACH_UPSTREAM: {
|
||||
req_failed_to_reach_upstream += amount;
|
||||
break;
|
||||
}
|
||||
case ngx_http_plugin_metric_type_e::CPU_USAGE: {
|
||||
cpu_event.setCPU(amount);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dbgWarning(D_METRICS_NGINX_ATTACHMENT)
|
||||
<< "Unsupported metric type. Type: " << static_cast<int>(metric_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nginxIntakerEvent::getPluginMetricCounter(ngx_http_plugin_metric_type_e metric_type) const
|
||||
{
|
||||
switch (metric_type) {
|
||||
case ngx_http_plugin_metric_type_e::INSPECTION_SUCCESSES_COUNT:
|
||||
return successfull_inspection_counter;
|
||||
case ngx_http_plugin_metric_type_e::INSPECTION_OPEN_FAILURES_COUNT:
|
||||
return open_failure_inspection_counter;
|
||||
case ngx_http_plugin_metric_type_e::INSPECTION_CLOSE_FAILURES_COUNT:
|
||||
return close_failure_inspection_counter;
|
||||
case ngx_http_plugin_metric_type_e::TRANSPARENTS_COUNT:
|
||||
return transparent_mode_counter;
|
||||
case ngx_http_plugin_metric_type_e::TOTAL_TRANSPARENTS_TIME:
|
||||
return total_transparent_time;
|
||||
case ngx_http_plugin_metric_type_e::INSPECT_VERDICTS_COUNT:
|
||||
return inspect_verdict_counter;
|
||||
case ngx_http_plugin_metric_type_e::ACCEPT_VERDICTS_COUNT:
|
||||
return accept_verdict_counter;
|
||||
case ngx_http_plugin_metric_type_e::DROP_VERDICTS_COUNT:
|
||||
return drop_verdict_counter;
|
||||
case ngx_http_plugin_metric_type_e::INJECT_VERDICTS_COUNT:
|
||||
return inject_verdict_counter;
|
||||
case ngx_http_plugin_metric_type_e::IRRELEVANT_VERDICTS_COUNT:
|
||||
return irrelevant_verdict_counter;
|
||||
case ngx_http_plugin_metric_type_e::RECONF_VERDICTS_COUNT:
|
||||
return reconf_verdict_counter;
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return average_overall_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::MAX_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return max_overall_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::MIN_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return min_overall_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_REQ_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return average_req_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::MAX_REQ_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return max_req_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::MIN_REQ_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return min_req_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return average_res_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return max_res_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT:
|
||||
return min_res_processing_time_until_verdict;
|
||||
case ngx_http_plugin_metric_type_e::REQ_FAILED_COMPRESSION_COUNT:
|
||||
return req_failed_compression_counter;
|
||||
case ngx_http_plugin_metric_type_e::RES_FAILED_COMPRESSION_COUNT:
|
||||
return res_failed_compression_counter;
|
||||
case ngx_http_plugin_metric_type_e::REQ_FAILED_DECOMPRESSION_COUNT:
|
||||
return req_failed_decompression_counter;
|
||||
case ngx_http_plugin_metric_type_e::RES_FAILED_DECOMPRESSION_COUNT:
|
||||
return res_failed_decompression_counter;
|
||||
case ngx_http_plugin_metric_type_e::REQ_SUCCESSFUL_COMPRESSION_COUNT:
|
||||
return req_successful_compression_counter;
|
||||
case ngx_http_plugin_metric_type_e::RES_SUCCESSFUL_COMPRESSION_COUNT:
|
||||
return res_successful_compression_counter;
|
||||
case ngx_http_plugin_metric_type_e::REQ_SUCCESSFUL_DECOMPRESSION_COUNT:
|
||||
return req_successful_decompression_counter;
|
||||
case ngx_http_plugin_metric_type_e::RES_SUCCESSFUL_DECOMPRESSION_COUNT:
|
||||
return res_successful_decompression_counter;
|
||||
case ngx_http_plugin_metric_type_e::CORRUPTED_ZIP_SKIPPED_SESSION_COUNT:
|
||||
return corrupted_zip_skipped_session_counter;
|
||||
case ngx_http_plugin_metric_type_e::THREAD_TIMEOUT:
|
||||
return thread_timeout;
|
||||
case ngx_http_plugin_metric_type_e::REG_THREAD_TIMEOUT:
|
||||
return reg_thread_timeout;
|
||||
case ngx_http_plugin_metric_type_e::REQ_HEADER_THREAD_TIMEOUT:
|
||||
return req_header_thread_timeout;
|
||||
case ngx_http_plugin_metric_type_e::REQ_BODY_THREAD_TIMEOUT:
|
||||
return req_body_thread_timeout;
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_REQ_BODY_SIZE_UPON_TIMEOUT:
|
||||
return average_req_body_size_upon_timeout;
|
||||
case ngx_http_plugin_metric_type_e::MAX_REQ_BODY_SIZE_UPON_TIMEOUT:
|
||||
return max_req_body_size_upon_timeout;
|
||||
case ngx_http_plugin_metric_type_e::MIN_REQ_BODY_SIZE_UPON_TIMEOUT:
|
||||
return min_req_body_size_upon_timeout;
|
||||
case ngx_http_plugin_metric_type_e::RES_HEADER_THREAD_TIMEOUT:
|
||||
return res_header_thread_timeout;
|
||||
case ngx_http_plugin_metric_type_e::RES_BODY_THREAD_TIMEOUT:
|
||||
return res_body_thread_timeout;
|
||||
case ngx_http_plugin_metric_type_e::AVERAGE_RES_BODY_SIZE_UPON_TIMEOUT:
|
||||
return average_res_body_size_upon_timeout;
|
||||
case ngx_http_plugin_metric_type_e::MAX_RES_BODY_SIZE_UPON_TIMEOUT:
|
||||
return max_res_body_size_upon_timeout;
|
||||
case ngx_http_plugin_metric_type_e::MIN_RES_BODY_SIZE_UPON_TIMEOUT:
|
||||
return min_res_body_size_upon_timeout;
|
||||
case ngx_http_plugin_metric_type_e::THREAD_FAILURE:
|
||||
return thread_failure;
|
||||
case ngx_http_plugin_metric_type_e::REQ_PROCCESSING_TIMEOUT:
|
||||
return req_proccessing_timeout;
|
||||
case ngx_http_plugin_metric_type_e::RES_PROCCESSING_TIMEOUT:
|
||||
return res_proccessing_timeout;
|
||||
case ngx_http_plugin_metric_type_e::REQ_FAILED_TO_REACH_UPSTREAM:
|
||||
return req_failed_to_reach_upstream;
|
||||
case ngx_http_plugin_metric_type_e::CPU_USAGE:
|
||||
return static_cast<uint64_t>(cpu_event.getCPU());
|
||||
default:
|
||||
dbgWarning(D_METRICS_NGINX_ATTACHMENT)
|
||||
<< "Unsupported metric type. Type: " << static_cast<int>(metric_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nginxIntakerMetric::upon(const nginxIntakerEvent &event)
|
||||
{
|
||||
successfull_inspection_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::INSPECTION_SUCCESSES_COUNT)
|
||||
);
|
||||
transparent_mode_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::TRANSPARENTS_COUNT)
|
||||
);
|
||||
total_transparent_time.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::TOTAL_TRANSPARENTS_TIME)
|
||||
);
|
||||
open_failure_inspection_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::INSPECTION_OPEN_FAILURES_COUNT)
|
||||
);
|
||||
close_failure_inspection_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::INSPECTION_CLOSE_FAILURES_COUNT)
|
||||
);
|
||||
inject_verdict_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::INJECT_VERDICTS_COUNT)
|
||||
);
|
||||
inspect_verdict_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::INSPECT_VERDICTS_COUNT)
|
||||
);
|
||||
accept_verdict_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::ACCEPT_VERDICTS_COUNT)
|
||||
);
|
||||
drop_verdict_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::DROP_VERDICTS_COUNT)
|
||||
);
|
||||
irrelevant_verdict_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::IRRELEVANT_VERDICTS_COUNT)
|
||||
);
|
||||
reconf_verdict_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RECONF_VERDICTS_COUNT)
|
||||
);
|
||||
average_overall_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::AVERAGE_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
max_overall_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MAX_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
min_overall_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MIN_OVERALL_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
average_req_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::AVERAGE_REQ_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
max_req_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MAX_REQ_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
min_req_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MIN_REQ_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
average_res_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::AVERAGE_RES_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
max_res_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MAX_RES_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
min_res_processing_time_until_verdict.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MIN_RES_PPROCESSING_TIME_UNTIL_VERDICT)
|
||||
);
|
||||
req_failed_compression_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_FAILED_COMPRESSION_COUNT)
|
||||
);
|
||||
res_failed_compression_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RES_FAILED_COMPRESSION_COUNT)
|
||||
);
|
||||
req_failed_decompression_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_FAILED_DECOMPRESSION_COUNT)
|
||||
);
|
||||
res_failed_decompression_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RES_FAILED_DECOMPRESSION_COUNT)
|
||||
);
|
||||
req_successful_compression_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_SUCCESSFUL_COMPRESSION_COUNT)
|
||||
);
|
||||
res_successful_compression_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RES_SUCCESSFUL_COMPRESSION_COUNT)
|
||||
);
|
||||
req_successful_decompression_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_SUCCESSFUL_DECOMPRESSION_COUNT)
|
||||
);
|
||||
res_successful_decompression_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RES_SUCCESSFUL_DECOMPRESSION_COUNT)
|
||||
);
|
||||
corrupted_zip_skipped_session_counter.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::CORRUPTED_ZIP_SKIPPED_SESSION_COUNT)
|
||||
);
|
||||
thread_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::THREAD_TIMEOUT)
|
||||
);
|
||||
reg_thread_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REG_THREAD_TIMEOUT)
|
||||
);
|
||||
req_header_thread_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_HEADER_THREAD_TIMEOUT)
|
||||
);
|
||||
req_body_thread_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_BODY_THREAD_TIMEOUT)
|
||||
);
|
||||
average_req_body_size_upon_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::AVERAGE_REQ_BODY_SIZE_UPON_TIMEOUT)
|
||||
);
|
||||
max_req_body_size_upon_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MAX_REQ_BODY_SIZE_UPON_TIMEOUT)
|
||||
);
|
||||
min_req_body_size_upon_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MIN_REQ_BODY_SIZE_UPON_TIMEOUT)
|
||||
);
|
||||
res_header_thread_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RES_HEADER_THREAD_TIMEOUT)
|
||||
);
|
||||
res_body_thread_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RES_BODY_THREAD_TIMEOUT)
|
||||
);
|
||||
average_res_body_size_upon_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::AVERAGE_RES_BODY_SIZE_UPON_TIMEOUT)
|
||||
);
|
||||
max_res_body_size_upon_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MAX_RES_BODY_SIZE_UPON_TIMEOUT)
|
||||
);
|
||||
min_res_body_size_upon_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::MIN_RES_BODY_SIZE_UPON_TIMEOUT)
|
||||
);
|
||||
thread_failure.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::THREAD_FAILURE)
|
||||
);
|
||||
req_proccessing_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_PROCCESSING_TIMEOUT)
|
||||
);
|
||||
res_proccessing_timeout.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::RES_PROCCESSING_TIMEOUT)
|
||||
);
|
||||
req_failed_to_reach_upstream.report(
|
||||
event.getPluginMetricCounter(ngx_http_plugin_metric_type_e::REQ_FAILED_TO_REACH_UPSTREAM)
|
||||
);
|
||||
event.notifyCPU();
|
||||
}
|
||||
369
components/attachment-intakers/nginx_attachment/nginx_parser.cc
Executable file
369
components/attachment-intakers/nginx_attachment/nginx_parser.cc
Executable file
@@ -0,0 +1,369 @@
|
||||
// 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 "nginx_parser.h"
|
||||
|
||||
#include "config.h"
|
||||
#include <algorithm>
|
||||
#include "connkey.h"
|
||||
#include "compression_utils.h"
|
||||
#include "nginx_attachment.h"
|
||||
#include "nginx_attachment_opaque.h"
|
||||
#include "user_identifiers_config.h"
|
||||
#include "debug.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_ATTACHMENT_PARSER);
|
||||
|
||||
Buffer NginxParser::tenant_header_key = Buffer();
|
||||
static const Buffer proxy_ip_header_key("X-Forwarded-For", 15, Buffer::MemoryType::STATIC);
|
||||
static const Buffer source_ip("sourceip", 8, Buffer::MemoryType::STATIC);
|
||||
|
||||
map<Buffer, CompressionType> NginxParser::content_encodings = {
|
||||
{Buffer("identity"), CompressionType::NO_COMPRESSION},
|
||||
{Buffer("gzip"), CompressionType::GZIP},
|
||||
{Buffer("deflate"), CompressionType::ZLIB}
|
||||
};
|
||||
|
||||
Maybe<HttpTransactionData>
|
||||
NginxParser::parseStartTrasaction(const Buffer &data)
|
||||
{
|
||||
return HttpTransactionData::createTransactionData(data);
|
||||
}
|
||||
|
||||
Maybe<ResponseCode>
|
||||
NginxParser::parseResponseCode(const Buffer &data)
|
||||
{
|
||||
if (data.size() < sizeof(uint16_t)) {
|
||||
dbgWarning(D_NGINX_ATTACHMENT_PARSER) << "Failed to get response code";
|
||||
return genError("Response code size is lower than uint16_t");
|
||||
}
|
||||
|
||||
return reinterpret_cast<const uint16_t *>(data.data())[0];
|
||||
}
|
||||
|
||||
Maybe<uint64_t>
|
||||
NginxParser::parseContentLength(const Buffer &data)
|
||||
{
|
||||
if (data.size() < sizeof(uint64_t)) {
|
||||
dbgWarning(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Failed to get content length";
|
||||
return genError("Content length size is lower than uint64");
|
||||
}
|
||||
return **data.getTypePtr<uint64_t>(0);
|
||||
}
|
||||
|
||||
Maybe<Buffer>
|
||||
genHeaderPart(const Buffer &raw_data, uint16_t &cur_pos)
|
||||
{
|
||||
if (cur_pos >= raw_data.size()) return genError("Current header data possession is after header part end");
|
||||
|
||||
auto value = raw_data.getTypePtr<uint16_t>(cur_pos);
|
||||
|
||||
if (!value.ok()) {
|
||||
return genError("Failed to get header part size: " + value.getErr());
|
||||
}
|
||||
|
||||
uint16_t part_len = *(value.unpack());
|
||||
cur_pos += sizeof(uint16_t);
|
||||
if (cur_pos + part_len > raw_data.size()) return genError("Header data extends beyond current buffer");
|
||||
|
||||
const u_char *part_data = raw_data.data();
|
||||
Buffer header_part(part_data + cur_pos, part_len, Buffer::MemoryType::VOLATILE);
|
||||
|
||||
cur_pos += part_len;
|
||||
|
||||
return header_part;
|
||||
}
|
||||
|
||||
Maybe<vector<HttpHeader>>
|
||||
genHeaders(const Buffer &raw_data)
|
||||
{
|
||||
dbgFlow(D_NGINX_ATTACHMENT_PARSER) << "Generating headers";
|
||||
|
||||
uint16_t cur_pos = 0;
|
||||
auto is_last_header_data = raw_data.getTypePtr<uint8_t>(cur_pos);
|
||||
if (!is_last_header_data.ok()) {
|
||||
return genError("Failed to get 'is last header' value: " + is_last_header_data.getErr());
|
||||
}
|
||||
|
||||
bool is_last_header = *(is_last_header_data.unpack()) == 1;
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Current header bulk "
|
||||
<< (is_last_header ? "contains " : "does not contain ")
|
||||
<< "last header";
|
||||
|
||||
cur_pos += sizeof(uint8_t);
|
||||
auto part_count = raw_data.getTypePtr<uint8_t>(cur_pos);
|
||||
if (!part_count.ok()) {
|
||||
return genError("Failed to get part count value: " + part_count.getErr());
|
||||
}
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Current header bulk index: " << to_string(*(part_count.unpack()));
|
||||
|
||||
static const string key_val_desc[] = {"key", "value"};
|
||||
Maybe<Buffer> header[2] = {Buffer(), Buffer()};
|
||||
vector<HttpHeader> headers;
|
||||
|
||||
cur_pos += sizeof(uint8_t);
|
||||
uint8_t cur_part = *(part_count.unpack());
|
||||
while (cur_pos < raw_data.size()) {
|
||||
for (int i = 0 ; i < 2 ; i ++) {
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Generating"
|
||||
<< (is_last_header ? " last " : " ")
|
||||
<< "header's "
|
||||
<< key_val_desc[i];
|
||||
|
||||
header[i] = genHeaderPart(raw_data, cur_pos);
|
||||
if (!header[i].ok()) {
|
||||
return genError("Failed to generate header's " + key_val_desc[i] + ":" + header[i].getErr());
|
||||
}
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Successfully generated header part. Header part type:"
|
||||
<< key_val_desc[i]
|
||||
<< ", data: '"
|
||||
<< dumpHex(header[i].unpack())
|
||||
<< "', size: "
|
||||
<< header[i].unpack().size();
|
||||
}
|
||||
|
||||
// is_last_header in bulk relates only to the last header in the bulk.
|
||||
headers.emplace_back(
|
||||
header[0].unpack(),
|
||||
header[1].unpack(),
|
||||
cur_part,
|
||||
cur_pos >= raw_data.size() && is_last_header
|
||||
);
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "end pos: " << cur_pos;
|
||||
cur_part++;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
Maybe<vector<HttpHeader>>
|
||||
NginxParser::parseRequestHeaders(const Buffer &data)
|
||||
{
|
||||
auto parsed_headers = genHeaders(data);
|
||||
if (!parsed_headers.ok()) return parsed_headers.passErr();
|
||||
|
||||
auto i_transaction_table = Singleton::Consume<I_TableSpecific<SessionID>>::by<NginxAttachment>();
|
||||
|
||||
for (const HttpHeader &header : *parsed_headers) {
|
||||
auto source_identifiers = getConfigurationWithDefault<UsersAllIdentifiersConfig>(
|
||||
UsersAllIdentifiersConfig(),
|
||||
"rulebase",
|
||||
"usersIdentifiers"
|
||||
);
|
||||
source_identifiers.parseRequestHeaders(header);
|
||||
|
||||
NginxAttachmentOpaque &opaque = i_transaction_table->getState<NginxAttachmentOpaque>();
|
||||
opaque.addToSavedData(
|
||||
HttpTransactionData::req_headers,
|
||||
static_cast<string>(header.getKey()) + ": " + static_cast<string>(header.getValue()) + "\r\n"
|
||||
);
|
||||
|
||||
if (NginxParser::tenant_header_key == header.getKey()) {
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Identified active tenant header. Key: "
|
||||
<< dumpHex(header.getKey())
|
||||
<< ", Value: "
|
||||
<< dumpHex(header.getValue());
|
||||
|
||||
string active_tenant(static_cast<string>(header.getValue()));
|
||||
opaque.setSessionTenant(active_tenant);
|
||||
} else if (proxy_ip_header_key == header.getKey()) {
|
||||
source_identifiers.setXFFValuesToOpaqueCtx(header, UsersAllIdentifiersConfig::ExtractType::PROXYIP);
|
||||
}
|
||||
}
|
||||
|
||||
return parsed_headers;
|
||||
}
|
||||
|
||||
Maybe<vector<HttpHeader>>
|
||||
NginxParser::parseResponseHeaders(const Buffer &data)
|
||||
{
|
||||
return genHeaders(data);
|
||||
}
|
||||
|
||||
Maybe<Buffer>
|
||||
decompressBuffer(CompressionStream *compression_stream, const Buffer &compressed_buffer)
|
||||
{
|
||||
if (compressed_buffer.size() == 0) return Buffer();
|
||||
|
||||
auto compression_result = decompressData(compression_stream, compressed_buffer.size(), compressed_buffer.data());
|
||||
if (!compression_result.ok) return genError("Failed to decompress data");
|
||||
|
||||
if (compression_result.output == nullptr) return Buffer();;
|
||||
|
||||
Buffer decompressed_buffer(
|
||||
compression_result.output,
|
||||
compression_result.num_output_bytes,
|
||||
Buffer::MemoryType::OWNED
|
||||
);
|
||||
free(compression_result.output);
|
||||
|
||||
return decompressed_buffer;
|
||||
}
|
||||
|
||||
Maybe<Buffer>
|
||||
parseCompressedHttpBodyData(CompressionStream *compression_stream, const Buffer &body_raw_data)
|
||||
{
|
||||
if (compression_stream == nullptr) return genError("Cannot decompress body without compression stream");
|
||||
|
||||
Maybe<Buffer> decompressed_buffer_maybe = decompressBuffer(compression_stream, body_raw_data);
|
||||
if (!decompressed_buffer_maybe.ok()) {
|
||||
return genError("Failed to decompress buffer. Error: " + decompressed_buffer_maybe.getErr());
|
||||
}
|
||||
|
||||
return decompressed_buffer_maybe.unpack();
|
||||
}
|
||||
|
||||
Maybe<HttpBody>
|
||||
genBody(const Buffer &raw_response_body, CompressionStream *compression_stream = nullptr)
|
||||
{
|
||||
uint offset = 0;
|
||||
auto is_last_part_maybe = raw_response_body.getTypePtr<uint8_t>(offset);
|
||||
if (!is_last_part_maybe.ok()) {
|
||||
return genError("Failed to get 'is last part' value: " + is_last_part_maybe.getErr());
|
||||
}
|
||||
bool is_last_part = *is_last_part_maybe.unpack();
|
||||
|
||||
offset += sizeof(uint8_t);
|
||||
auto part_count_maybe = raw_response_body.getTypePtr<uint8_t>(offset);
|
||||
if (!part_count_maybe.ok()) {
|
||||
return genError("Failed to get part count value: " + part_count_maybe.getErr());
|
||||
}
|
||||
uint8_t body_chunk_index = *part_count_maybe.unpack();
|
||||
|
||||
offset += sizeof(uint8_t);
|
||||
Buffer body_raw_data(
|
||||
raw_response_body.data() + offset,
|
||||
raw_response_body.size() - offset,
|
||||
Buffer::MemoryType::VOLATILE
|
||||
);
|
||||
|
||||
if (compression_stream == nullptr) {
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Successfully generated body chunk from non compressed buffer";
|
||||
return HttpBody(body_raw_data, is_last_part, body_chunk_index);
|
||||
}
|
||||
|
||||
Maybe<Buffer> body_data_maybe = parseCompressedHttpBodyData(compression_stream, body_raw_data);
|
||||
if (!body_data_maybe.ok()) {
|
||||
dbgWarning(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Failed to decompress body chunk. Chunk index: "
|
||||
<< to_string(body_chunk_index)
|
||||
<< ", raw input size: "
|
||||
<< body_raw_data.size();
|
||||
return genError("Failed to parse HTTP body data: " + body_data_maybe.getErr());
|
||||
}
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Successfully generated decompressed body chunk. Compressed original size: "
|
||||
<< body_raw_data.size();
|
||||
|
||||
return HttpBody(body_data_maybe.unpack(), is_last_part, body_chunk_index);
|
||||
}
|
||||
|
||||
Maybe<HttpBody>
|
||||
NginxParser::parseRequestBody(const Buffer &data)
|
||||
{
|
||||
Maybe<HttpBody> body = genBody(data);
|
||||
if (!body.ok()) return genError("Failed to generate body from buffer: " + body.getErr());
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Successfully generated request body chunk. Chunk index: "
|
||||
<< to_string(body.unpack().getBodyChunkIndex())
|
||||
<< ", is last chunk: "
|
||||
<< (body.unpack().isLastChunk() ? "true" : "false")
|
||||
<< ", size: "
|
||||
<< body.unpack().getData().size()
|
||||
<< ", value: "
|
||||
<< dumpHex(body.unpack().getData());
|
||||
|
||||
auto i_transaction_table = Singleton::Consume<I_TableSpecific<SessionID>>::by<NginxAttachment>();
|
||||
auto &state = i_transaction_table->getState<NginxAttachmentOpaque>();
|
||||
state.setSavedData(HttpTransactionData::req_body, (*body).getData());
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
Maybe<HttpBody>
|
||||
NginxParser::parseResponseBody(const Buffer &raw_response_body, CompressionStream *compression_stream)
|
||||
{
|
||||
Maybe<HttpBody> body = genBody(raw_response_body, compression_stream);
|
||||
if (!body.ok()) return genError("Failed to generate body from buffer: " + body.getErr());
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Successfully generated response body chunk. Chunk index: "
|
||||
<< to_string(body.unpack().getBodyChunkIndex())
|
||||
<< ", is last chunk: "
|
||||
<< (body.unpack().isLastChunk() ? "true" : "false")
|
||||
<< ", size: "
|
||||
<< body.unpack().getData().size()
|
||||
<< ", value: "
|
||||
<< dumpHex(body.unpack().getData());;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
Maybe<CompressionType>
|
||||
NginxParser::parseContentEncoding(const vector<HttpHeader> &headers)
|
||||
{
|
||||
static const Buffer content_encoding_header_key("Content-Encoding");
|
||||
|
||||
auto it = find_if(
|
||||
headers.begin(),
|
||||
headers.end(),
|
||||
[&] (const HttpHeader &http_header) { return http_header.getKey() == content_encoding_header_key; }
|
||||
);
|
||||
if (it == headers.end()) {
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Headers do not contain \"Content-Encoding\" header: "
|
||||
<< "body is expected to be plain-text";
|
||||
|
||||
return CompressionType::NO_COMPRESSION;
|
||||
}
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Found header with key \"Content-Encoding\". Value: "
|
||||
<< dumpHex((*it).getValue());
|
||||
auto content_encoding_maybe = convertToContentEncoding((*it).getValue());
|
||||
if (!content_encoding_maybe.ok()) {
|
||||
return genError(
|
||||
"Failed to parse value of \"Content-Encoding\" header: " +
|
||||
content_encoding_maybe.getErr()
|
||||
);
|
||||
}
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Successfully parsed value of \"Content-Encoding\" header";
|
||||
|
||||
return content_encoding_maybe.unpack();
|
||||
}
|
||||
|
||||
Maybe<CompressionType>
|
||||
NginxParser::convertToContentEncoding(const Buffer &content_encoding_header_value)
|
||||
{
|
||||
if (content_encoding_header_value.contains(',')) {
|
||||
return genError("Multiple content encodings for a specific HTTP request/response body are not supported");
|
||||
}
|
||||
|
||||
if (content_encodings.find(content_encoding_header_value) == content_encodings.end()) {
|
||||
return genError(
|
||||
"Unsupported or undefined \"Content-Encoding\" value: " +
|
||||
static_cast<string>(content_encoding_header_value)
|
||||
);
|
||||
}
|
||||
return content_encodings[content_encoding_header_value];
|
||||
}
|
||||
45
components/attachment-intakers/nginx_attachment/nginx_parser.h
Executable file
45
components/attachment-intakers/nginx_attachment/nginx_parser.h
Executable file
@@ -0,0 +1,45 @@
|
||||
// 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 __NGINX_PARSER_H__
|
||||
#define __NGINX_PARSER_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "compression_utils.h"
|
||||
#include "nginx_attachment_common.h"
|
||||
#include "http_transaction_common.h"
|
||||
#include "http_inspection_events.h"
|
||||
#include "i_encryptor.h"
|
||||
|
||||
class NginxParser : Singleton::Consume<I_Encryptor>
|
||||
{
|
||||
public:
|
||||
static Maybe<HttpTransactionData> parseStartTrasaction(const Buffer &data);
|
||||
static Maybe<ResponseCode> parseResponseCode(const Buffer &data);
|
||||
static Maybe<uint64_t> parseContentLength(const Buffer &data);
|
||||
static Maybe<std::vector<HttpHeader>> parseRequestHeaders(const Buffer &data);
|
||||
static Maybe<std::vector<HttpHeader>> parseResponseHeaders(const Buffer &data);
|
||||
static Maybe<HttpBody> parseRequestBody(const Buffer &data);
|
||||
static Maybe<HttpBody> parseResponseBody(const Buffer &raw_response_body, CompressionStream *compression_stream);
|
||||
static Maybe<CompressionType> parseContentEncoding(const std::vector<HttpHeader> &headers);
|
||||
|
||||
static Buffer tenant_header_key;
|
||||
|
||||
private:
|
||||
static Maybe<CompressionType> convertToContentEncoding(const Buffer &content_encoding_header_value);
|
||||
|
||||
static std::map<Buffer, CompressionType> content_encodings;
|
||||
};
|
||||
|
||||
#endif // __NGINX_PARSER_H__
|
||||
447
components/attachment-intakers/nginx_attachment/user_identifiers_config.cc
Executable file
447
components/attachment-intakers/nginx_attachment/user_identifiers_config.cc
Executable file
@@ -0,0 +1,447 @@
|
||||
// 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 "user_identifiers_config.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "nginx_attachment.h"
|
||||
#include "nginx_attachment_opaque.h"
|
||||
#include "nginx_parser.h"
|
||||
#include "cidrs_data.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_ATTACHMENT_PARSER);
|
||||
|
||||
static const Buffer header_key("headerkey", 9, Buffer::MemoryType::STATIC);
|
||||
static const Buffer jwt("authorization", 13, Buffer::MemoryType::STATIC);
|
||||
static const Buffer xff("x-forwarded-for", 15, Buffer::MemoryType::STATIC);
|
||||
static const Buffer cookie("cookie", 6, Buffer::MemoryType::STATIC);
|
||||
static const Buffer source_ip("sourceip", 8, Buffer::MemoryType::STATIC);
|
||||
static const Buffer oauth("_oauth2_proxy", 13, Buffer::MemoryType::STATIC);
|
||||
static const Buffer empty_buffer("", 0, Buffer::MemoryType::STATIC);
|
||||
|
||||
const static string jwt_prefix = "Bearer ";
|
||||
|
||||
UsersAllIdentifiersConfig::UsersIdentifiersConfig::UsersIdentifiersConfig() : source_identifier(source_ip){};
|
||||
|
||||
UsersAllIdentifiersConfig::UsersIdentifiersConfig::UsersIdentifiersConfig(const std::string &identifier)
|
||||
:
|
||||
source_identifier(identifier)
|
||||
{}
|
||||
|
||||
bool
|
||||
UsersAllIdentifiersConfig::UsersIdentifiersConfig::operator==(const UsersIdentifiersConfig &other) const
|
||||
{
|
||||
return source_identifier == other.source_identifier;
|
||||
}
|
||||
|
||||
void
|
||||
UsersAllIdentifiersConfig::UsersIdentifiersConfig::load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
parseJSONKey<string>("sourceIdentifier", source_identifier, ar);
|
||||
parseJSONKey<vector<string>>("identifierValues", identifier_values, ar);
|
||||
}
|
||||
|
||||
bool
|
||||
UsersAllIdentifiersConfig::UsersIdentifiersConfig::isEqualSourceIdentifier(const string &other) const
|
||||
{
|
||||
if (source_identifier.size() != other.size()) return false;
|
||||
return equal(
|
||||
source_identifier.begin(),
|
||||
source_identifier.end(),
|
||||
other.begin(),
|
||||
[] (char c1, char c2) { return tolower(c1) == tolower(c2); }
|
||||
);
|
||||
}
|
||||
|
||||
UsersAllIdentifiersConfig::UsersAllIdentifiersConfig()
|
||||
{
|
||||
}
|
||||
|
||||
vector<string>
|
||||
UsersAllIdentifiersConfig::getHeaderValuesFromConfig(const string &header_key) const
|
||||
{
|
||||
for (auto user_identifier : user_identifiers) {
|
||||
if (user_identifier.isEqualSourceIdentifier(header_key)) {
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Match source identifier is found";
|
||||
return user_identifier.getIdentifierValues();
|
||||
}
|
||||
}
|
||||
return vector<string>();
|
||||
}
|
||||
|
||||
void
|
||||
UsersAllIdentifiersConfig::load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
vector<UsersIdentifiersConfig> tmp_user_identifiers;
|
||||
parseJSONKey<vector<UsersIdentifiersConfig>>("sourceIdentifiers", tmp_user_identifiers, ar);
|
||||
|
||||
user_identifiers.clear();
|
||||
user_identifiers.reserve(tmp_user_identifiers.size() + 1);
|
||||
for (auto &identifier : tmp_user_identifiers) {
|
||||
if (identifier.getSourceIdentifier() == header_key) {
|
||||
for (const auto &header : identifier.getIdentifierValues()) {
|
||||
user_identifiers.emplace_back(header);
|
||||
}
|
||||
} else {
|
||||
user_identifiers.push_back(identifier);
|
||||
}
|
||||
}
|
||||
|
||||
vector<UsersIdentifiersConfig> default_order = {
|
||||
UsersIdentifiersConfig(cookie),
|
||||
UsersIdentifiersConfig(jwt),
|
||||
UsersIdentifiersConfig(xff)
|
||||
};
|
||||
|
||||
auto last_user_defined_header = find_first_of(
|
||||
default_order.rbegin(),
|
||||
default_order.rend(),
|
||||
user_identifiers.begin(),
|
||||
user_identifiers.end()
|
||||
);
|
||||
if (last_user_defined_header == default_order.rend()) {
|
||||
user_identifiers.insert(user_identifiers.end(), default_order.begin(), default_order.end());
|
||||
} else {
|
||||
auto last_defined_forwards = find(default_order.begin(), default_order.end(), *last_user_defined_header);
|
||||
user_identifiers.insert(user_identifiers.end(), last_defined_forwards + 1, default_order.end());
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
compareBufferWithoutCase(const Buffer &b1, const Buffer &b2)
|
||||
{
|
||||
if (b1.size() != b2.size()) return false;
|
||||
return equal(b1.begin(), b1.end(), b2.begin(), [] (u_char c1, u_char c2) { return tolower(c1) == tolower(c2); });
|
||||
}
|
||||
|
||||
void
|
||||
UsersAllIdentifiersConfig::setIdentifierTopaqueCtx(const HttpHeader &header) const
|
||||
{
|
||||
if (compareBufferWithoutCase(jwt, header.getKey())) {
|
||||
setJWTValuesToOpaqueCtx(header);
|
||||
} else if (compareBufferWithoutCase(xff, header.getKey())) {
|
||||
setXFFValuesToOpaqueCtx(header, ExtractType::SOURCEIDENTIFIER);
|
||||
} else if (compareBufferWithoutCase(cookie, header.getKey())) {
|
||||
setCookieValuesToOpaqueCtx(header);
|
||||
} else {
|
||||
setCustomHeaderToOpaqueCtx(header);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
UsersAllIdentifiersConfig::isHigherPriority(const string ¤t_identifier, const string &header_key) const
|
||||
{
|
||||
for (auto user_identifier : user_identifiers) {
|
||||
if (user_identifier.isEqualSourceIdentifier(current_identifier)) return false;
|
||||
if (user_identifier.isEqualSourceIdentifier(header_key)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
UsersAllIdentifiersConfig::setJWTValuesToOpaqueCtx(const HttpHeader &header) const
|
||||
{
|
||||
const vector<string> jwt_values = getHeaderValuesFromConfig(header.getKey());
|
||||
if (jwt_values.size() == 0) {
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "No JWT keys exists in configuration";
|
||||
return;
|
||||
}
|
||||
if (bcmp(header.getValue().data(), jwt_prefix.c_str(), jwt_prefix.size()) != 0) {
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "Invalid JWT header, 'Bearer' prefix missing";
|
||||
return;
|
||||
}
|
||||
int start_dot = -1;
|
||||
int end_dot = -1;
|
||||
for (uint i = 0 ; i < header.getValue().size() ; i++) {
|
||||
if (header.getValue()[i] == '.') {
|
||||
if (start_dot < 0) {
|
||||
start_dot = i;
|
||||
} else if (end_dot < 0) {
|
||||
end_dot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (start_dot < 0 || end_dot < 0) {
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER) << "The header does not contain dots";
|
||||
return;
|
||||
}
|
||||
|
||||
string jwt_str(
|
||||
reinterpret_cast<const char *>(header.getValue().data()),
|
||||
start_dot + 1,
|
||||
end_dot - start_dot - 1
|
||||
);
|
||||
I_Encryptor *encryptor = Singleton::Consume<I_Encryptor>::by<NginxParser>();
|
||||
auto decoded_jwt = encryptor->base64Decode(jwt_str);
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Base64 decoded JWT: " << decoded_jwt;
|
||||
|
||||
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>();
|
||||
stringstream ss;
|
||||
ss.str(decoded_jwt);
|
||||
cereal::JSONInputArchive in_ar(ss);
|
||||
for (const string &field_name : jwt_values) {
|
||||
try {
|
||||
string tmp_val;
|
||||
in_ar(cereal::make_nvp(field_name, tmp_val));
|
||||
opaque.setSourceIdentifier(header.getKey(), tmp_val);
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Added source identifir to context. Key: "
|
||||
<< field_name
|
||||
<< ". Value: "
|
||||
<< tmp_val;
|
||||
return;
|
||||
} catch (const cereal::Exception &e) {
|
||||
dbgTrace(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Unable to find value for the key: "
|
||||
<< field_name
|
||||
<< ". Error: "
|
||||
<< e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string
|
||||
stripOptionalPort(const string::const_iterator &first, const string::const_iterator &last)
|
||||
{
|
||||
// Microsoft XFF+IPv6+Port yikes - see also here https://github.com/eclipse/jetty.project/issues/3630
|
||||
if (*first == '[') {
|
||||
// Possible bracketed IPv6 address such as "[2001:db8::1]" + optional numeric ":<port>"
|
||||
auto close_bracket = find(first + 1, last, ']');
|
||||
if (close_bracket == last) return string(first, last);
|
||||
return string(first+1, close_bracket);
|
||||
}
|
||||
|
||||
auto first_colon = find(first, last, ':');
|
||||
if (first_colon == last) return string(first, last);
|
||||
|
||||
// If there is more than one colon it means its probably IPv6 address without brackets
|
||||
auto second_colon = find(first_colon + 1, last, ':');
|
||||
if (second_colon != last) return string(first, last);
|
||||
|
||||
// If there's only one colon it can't be IPv6 and can only be IPv4 with port
|
||||
return string(first, first_colon);
|
||||
}
|
||||
|
||||
static vector<string>
|
||||
split(const string &str)
|
||||
{
|
||||
vector<string> elems;
|
||||
elems.reserve(str.size() / 8 + 1);
|
||||
auto sub_start = str.cbegin(), sub_end = str.cbegin();
|
||||
for (auto iter = str.cbegin(); iter != str.cend(); ++iter) {
|
||||
if (isspace(*iter)) {
|
||||
if (sub_start == iter) {
|
||||
++sub_start;
|
||||
++sub_end;
|
||||
}
|
||||
} else if (*iter == ',') {
|
||||
if (sub_start != sub_end) {
|
||||
elems.push_back(stripOptionalPort(sub_start, sub_end));
|
||||
}
|
||||
sub_end = iter + 1;
|
||||
sub_start = iter + 1;
|
||||
} else {
|
||||
sub_end = iter + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (sub_start != sub_end) {
|
||||
elems.push_back(stripOptionalPort(sub_start, sub_end));
|
||||
}
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
static bool
|
||||
isIpTrusted(const string &value, const vector<CIDRSData> &cidr_values)
|
||||
{
|
||||
if (cidr_values.empty()) return true;
|
||||
|
||||
for(const auto &cidr_data : cidr_values) {
|
||||
if (cidr_data.contains(value)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
UsersAllIdentifiersConfig::parseXForwardedFor(const string &str) const
|
||||
{
|
||||
vector<string> header_values = split(str);
|
||||
|
||||
if (header_values.empty()) return genError("No IP found in the xff header list");
|
||||
|
||||
vector<string> xff_values = getHeaderValuesFromConfig("x-forwarded-for");
|
||||
vector<CIDRSData> cidr_values(xff_values.begin(), xff_values.end());
|
||||
|
||||
for (const string &value : header_values) {
|
||||
if (!IPAddr::createIPAddr(value).ok()) {
|
||||
dbgWarning(D_NGINX_ATTACHMENT_PARSER) << "Invalid IP address found in the xff header IPs list: " << value;
|
||||
return genError("Invalid IP address");
|
||||
}
|
||||
if (!isIpTrusted(value, cidr_values)) return genError("Untrusted Ip found");
|
||||
}
|
||||
|
||||
return header_values[0];
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UsersAllIdentifiersConfig::setXFFValuesToOpaqueCtx(const HttpHeader &header, ExtractType type) const
|
||||
{
|
||||
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)
|
||||
<< "Added source identifir to XFF "
|
||||
<< value.unpack();
|
||||
} else {
|
||||
opaque.setSavedData(HttpTransactionData::proxy_ip_ctx, value.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UsersAllIdentifiersConfig::setCustomHeaderToOpaqueCtx(const HttpHeader &header) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
i_transaction_table->getState<NginxAttachmentOpaque>().setSourceIdentifier(header.getKey(), header.getValue());
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER)
|
||||
<< "Added source identifir to custom header: "
|
||||
<< static_cast<string>(header.getValue());
|
||||
return;
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
UsersAllIdentifiersConfig::parseCookieElement(
|
||||
const string::const_iterator &start,
|
||||
const string::const_iterator &end,
|
||||
const string &key) const
|
||||
{
|
||||
auto curr_pos = start;
|
||||
|
||||
// Skip whitespace
|
||||
for (; curr_pos != end && isspace(*curr_pos); ++curr_pos);
|
||||
|
||||
// Check key
|
||||
for (auto key_pos = key.begin(); key_pos != key.end(); ++key_pos) {
|
||||
if (curr_pos == end || tolower(*curr_pos) != tolower(*key_pos)) return genError("Key value not found");
|
||||
++curr_pos;
|
||||
}
|
||||
|
||||
// Skip whitespace
|
||||
for (; curr_pos != end && isspace(*curr_pos); ++curr_pos);
|
||||
|
||||
// Check for '='
|
||||
if (curr_pos == end || *curr_pos != '=') return genError("Equal sign not found");
|
||||
++curr_pos;
|
||||
|
||||
// Skip whitespace
|
||||
for (; curr_pos != end && isspace(*curr_pos); ++curr_pos);
|
||||
|
||||
auto value_start = curr_pos;
|
||||
|
||||
// Read value
|
||||
for (; curr_pos != end && !isspace(*curr_pos); ++curr_pos);
|
||||
|
||||
auto value_end = curr_pos;
|
||||
|
||||
// Verify value read currectly - should be only whitespaces to the end;
|
||||
for (; curr_pos != end && isspace(*curr_pos); ++curr_pos);
|
||||
if (curr_pos != end) return genError("Unexpected characters when reading a value");
|
||||
|
||||
return string(value_start, value_end);
|
||||
}
|
||||
|
||||
Buffer
|
||||
UsersAllIdentifiersConfig::extractKeyValueFromCookie(const string &cookie_value, const string &key) const
|
||||
{
|
||||
auto curr_start = cookie_value.begin();
|
||||
auto end = cookie_value.end();
|
||||
|
||||
while (curr_start != end) {
|
||||
auto curr_end = find(curr_start, end, ';');
|
||||
auto res = parseCookieElement(curr_start, curr_end, key);
|
||||
if (res.ok()) {
|
||||
if (key != oauth) return *res;
|
||||
I_Encryptor *encryptor = Singleton::Consume<I_Encryptor>::by<NginxParser>();
|
||||
auto decoded_value = encryptor->base64Decode(*res);
|
||||
auto decoded_end = find(decoded_value.begin(), decoded_value.end(), '|');
|
||||
return Buffer(string(decoded_value.begin(), decoded_end));
|
||||
}
|
||||
|
||||
if (curr_end != end) ++curr_end;
|
||||
curr_start = curr_end;
|
||||
}
|
||||
|
||||
return empty_buffer;
|
||||
}
|
||||
|
||||
void
|
||||
UsersAllIdentifiersConfig::setCookieValuesToOpaqueCtx(const HttpHeader &header) const
|
||||
{
|
||||
vector<string> cookie_keys = getHeaderValuesFromConfig(header.getKey());
|
||||
cookie_keys.push_back(oauth);
|
||||
cookie_keys.push_back("jsessionid");
|
||||
for (const string &key : cookie_keys) {
|
||||
string value = extractKeyValueFromCookie(header.getValue(), key);
|
||||
if (!value.empty()) {
|
||||
dbgDebug(D_NGINX_ATTACHMENT_PARSER) << "Set source identifier from cookie: Oauth 2";
|
||||
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>();
|
||||
opaque.setSourceIdentifier(header.getKey(), value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UsersAllIdentifiersConfig::parseRequestHeaders(const HttpHeader &header) const
|
||||
{
|
||||
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>();
|
||||
const string ¤t_identifier = opaque.getSourceIdentifiersType();
|
||||
|
||||
if (!isHigherPriority(current_identifier, header.getKey())) return;
|
||||
|
||||
setIdentifierTopaqueCtx(header);
|
||||
}
|
||||
4
components/generic_rulebase/CMakeLists.txt
Executable file
4
components/generic_rulebase/CMakeLists.txt
Executable file
@@ -0,0 +1,4 @@
|
||||
add_definitions(-DUSERSPACE)
|
||||
|
||||
add_subdirectory(evaluators)
|
||||
add_library(generic_rulebase generic_rulebase.cc rulebase_config.cc triggers_config.cc parameters_config.cc generic_rulebase_context.cc zones_config.cc zone.cc assets_config.cc match_query.cc)
|
||||
137
components/generic_rulebase/assets_config.cc
Executable file
137
components/generic_rulebase/assets_config.cc
Executable file
@@ -0,0 +1,137 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "generic_rulebase/assets_config.h"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "generic_rulebase/generic_rulebase_utils.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "ip_utilities.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
void
|
||||
RuleAsset::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
archive_in(cereal::make_nvp("assetId", asset_id));
|
||||
archive_in(cereal::make_nvp("assetName", asset_name));
|
||||
archive_in(cereal::make_nvp("assetUrls", asset_urls));
|
||||
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Adding asset with UID: " << asset_id;
|
||||
}
|
||||
|
||||
void
|
||||
RuleAsset::AssetUrl::load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
archive_in(cereal::make_nvp("protocol", protocol));
|
||||
transform(protocol.begin(), protocol.end(), protocol.begin(), [](unsigned char c) { return tolower(c); });
|
||||
|
||||
archive_in(cereal::make_nvp("ip", ip));
|
||||
archive_in(cereal::make_nvp("port", port));
|
||||
|
||||
int value;
|
||||
if (protocol == "*") {
|
||||
is_any_proto = true;
|
||||
} else {
|
||||
is_any_proto = false;
|
||||
try {
|
||||
value = 0;
|
||||
if(protocol == "udp") value = IPPROTO_UDP;
|
||||
if(protocol == "tcp") value = IPPROTO_TCP;
|
||||
if(protocol == "dccp") value = IPPROTO_DCCP;
|
||||
if(protocol == "sctp") value = IPPROTO_SCTP;
|
||||
if(protocol == "icmp") value = IPPROTO_ICMP;
|
||||
if(protocol == "icmpv6") value = IPPROTO_ICMP;
|
||||
|
||||
if (value > static_cast<int>(UINT8_MAX) || value < 0) {
|
||||
dbgWarning(D_RULEBASE_CONFIG)
|
||||
<< "provided value is not a legal IP protocol number. Value: "
|
||||
<< protocol;
|
||||
} else {
|
||||
parsed_proto = value;
|
||||
}
|
||||
} catch (...) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "provided value is not a legal IP protocol. Value: " << protocol;
|
||||
}
|
||||
}
|
||||
|
||||
if (port == "*") {
|
||||
is_any_port = true;
|
||||
} else {
|
||||
is_any_port = false;
|
||||
try {
|
||||
value = stoi(port);
|
||||
if (value > static_cast<int>(UINT16_MAX) || value < 0) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "provided value is not a legal port number. Value: " << port;
|
||||
} else {
|
||||
parsed_port = value;
|
||||
}
|
||||
} catch (...) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "provided value is not a legal port. Value: " << port;
|
||||
}
|
||||
}
|
||||
|
||||
if (ip == "*") {
|
||||
is_any_ip = true;
|
||||
} else {
|
||||
is_any_ip = false;
|
||||
auto ip_addr = IPAddr::createIPAddr(ip);
|
||||
if (!ip_addr.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Could not create IP address. Error: " << ip_addr.getErr();
|
||||
} else {
|
||||
parsed_ip = ConvertToIpAddress(ip_addr.unpackMove());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpAddress
|
||||
RuleAsset::AssetUrl::ConvertToIpAddress(const IPAddr &addr)
|
||||
{
|
||||
IpAddress address;
|
||||
switch (addr.getType()) {
|
||||
case IPType::UNINITIALIZED: {
|
||||
address.addr4_t = {0};
|
||||
address.ip_type = IP_VERSION_ANY;
|
||||
break;
|
||||
}
|
||||
case IPType::V4: {
|
||||
address.addr4_t = addr.getIPv4();
|
||||
address.ip_type = IP_VERSION_4;
|
||||
break;
|
||||
}
|
||||
case IPType::V6: {
|
||||
address.addr6_t = addr.getIPv6();
|
||||
address.ip_type = IP_VERSION_6;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
address.addr4_t = {0};
|
||||
address.ip_type = IP_VERSION_ANY;
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Unsupported IP type: " << static_cast<int>(addr.getType());
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
const Assets Assets::empty_assets_config = Assets();
|
||||
|
||||
void
|
||||
Assets::preload()
|
||||
{
|
||||
registerExpectedSetting<Assets>("rulebase", "usedAssets");
|
||||
}
|
||||
1
components/generic_rulebase/evaluators/CMakeLists.txt
Executable file
1
components/generic_rulebase/evaluators/CMakeLists.txt
Executable file
@@ -0,0 +1 @@
|
||||
add_library(generic_rulebase_evaluators asset_eval.cc parameter_eval.cc practice_eval.cc query_eval.cc trigger_eval.cc zone_eval.cc connection_eval.cc http_transaction_data_eval.cc)
|
||||
40
components/generic_rulebase/evaluators/asset_eval.cc
Executable file
40
components/generic_rulebase/evaluators/asset_eval.cc
Executable file
@@ -0,0 +1,40 @@
|
||||
// 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;
|
||||
|
||||
string AssetMatcher::ctx_key = "asset_id";
|
||||
|
||||
AssetMatcher::AssetMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(AssetMatcher::getName(), params.size(), 1, 1);
|
||||
asset_id = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
AssetMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<AssetMatcher>();
|
||||
auto bc_asset_id_ctx = env->get<GenericConfigId>(AssetMatcher::ctx_key);
|
||||
|
||||
return bc_asset_id_ctx.ok() && *bc_asset_id_ctx == asset_id;
|
||||
}
|
||||
299
components/generic_rulebase/evaluators/connection_eval.cc
Executable file
299
components/generic_rulebase/evaluators/connection_eval.cc
Executable file
@@ -0,0 +1,299 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "generic_rulebase/evaluators/connection_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "ip_utilities.h"
|
||||
|
||||
using namespace std;
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
string IpAddressMatcher::ctx_key = "ipAddress";
|
||||
string SourceIpMatcher::ctx_key = "sourceIP";
|
||||
string DestinationIpMatcher::ctx_key = "destinationIP";
|
||||
string SourcePortMatcher::ctx_key = "sourcePort";
|
||||
string ListeningPortMatcher::ctx_key = "listeningPort";
|
||||
string IpProtocolMatcher::ctx_key = "ipProtocol";
|
||||
string UrlMatcher::ctx_key = "url";
|
||||
|
||||
Maybe<IPAddr>
|
||||
getIpAddrFromEnviroment(I_Environment *env, Context::MetaDataType enum_data_type, const string &str_data_type)
|
||||
{
|
||||
auto ip_str = env->get<string>(enum_data_type);
|
||||
if (!ip_str.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get " << str_data_type << " from the enviroment.";
|
||||
return genError("Failed to get " + str_data_type + " from the enviroment.");
|
||||
}
|
||||
return IPAddr::createIPAddr(ip_str.unpack());
|
||||
}
|
||||
|
||||
bool
|
||||
checkIfIpInRangesVec(const vector<CustomRange<IPAddr>> &values, const IPAddr &ip_to_check)
|
||||
{
|
||||
if (values.size() == 0) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip addersses vector empty. Match is true.";
|
||||
return true;
|
||||
}
|
||||
for (const CustomRange<IPAddr> &range : values) {
|
||||
if (range.contains(ip_to_check)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip adderss matched: " << ip_to_check;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip adderss not match: " << ip_to_check;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
IpAddressMatcher::IpAddressMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<IPAddr>> ip_range = CustomRange<IPAddr>::createRange(param);
|
||||
if (!ip_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create ip. Error: " + ip_range.getErr();
|
||||
continue;
|
||||
}
|
||||
values.push_back(ip_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
IpAddressMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<IpAddressMatcher>();
|
||||
Maybe<IPAddr> subject_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::SubjectIpAddr,
|
||||
"subject ip address"
|
||||
);
|
||||
if (subject_ip.ok() && checkIfIpInRangesVec(values, subject_ip.unpack())) return true;
|
||||
|
||||
Maybe<IPAddr> other_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::OtherIpAddr,
|
||||
"other ip address"
|
||||
);
|
||||
if (other_ip.ok() && checkIfIpInRangesVec(values, other_ip.unpack())) return true;
|
||||
if (!subject_ip.ok() && !other_ip.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Error in getting subject ip and other ip from the enviroment";
|
||||
return false;
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip adderss didn't match";
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceIpMatcher::SourceIpMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<IPAddr>> ip_range = CustomRange<IPAddr>::createRange(param);
|
||||
if (!ip_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create source ip. Error: " + ip_range.getErr();
|
||||
continue;
|
||||
}
|
||||
values.push_back(ip_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
SourceIpMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<SourceIpMatcher>();
|
||||
auto direction_maybe = env->get<string>(Context::MetaDataType::Direction);
|
||||
if (!direction_maybe.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get direction from the enviroment.";
|
||||
return false;
|
||||
}
|
||||
string direction = direction_maybe.unpack();
|
||||
if (direction == "incoming") {
|
||||
Maybe<IPAddr> other_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::OtherIpAddr,
|
||||
"other ip address"
|
||||
);
|
||||
return other_ip.ok() && checkIfIpInRangesVec(values, other_ip.unpack());
|
||||
} else if (direction == "outgoing") {
|
||||
Maybe<IPAddr> subject_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::SubjectIpAddr,
|
||||
"subject ip address"
|
||||
);
|
||||
return subject_ip.ok() && checkIfIpInRangesVec(values, subject_ip.unpack());
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Source ip adderss didn't match";
|
||||
return false;
|
||||
}
|
||||
|
||||
DestinationIpMatcher::DestinationIpMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<IPAddr>> ip_range = CustomRange<IPAddr>::createRange(param);
|
||||
if (!ip_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create destination ip. Error: " + ip_range.getErr();
|
||||
continue;
|
||||
}
|
||||
values.push_back(ip_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
DestinationIpMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<DestinationIpMatcher>();
|
||||
auto direction_maybe = env->get<string>(Context::MetaDataType::Direction);
|
||||
if (!direction_maybe.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get direction.";
|
||||
return false;
|
||||
}
|
||||
string direction = direction_maybe.unpack();
|
||||
if (direction == "outgoing") {
|
||||
Maybe<IPAddr> other_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::OtherIpAddr,
|
||||
"other ip address"
|
||||
);
|
||||
return other_ip.ok() && checkIfIpInRangesVec(values, other_ip.unpack());
|
||||
} else if (direction == "incoming") {
|
||||
Maybe<IPAddr> subject_ip = getIpAddrFromEnviroment(
|
||||
env,
|
||||
Context::MetaDataType::SubjectIpAddr,
|
||||
"subject ip address"
|
||||
);
|
||||
return subject_ip.ok() && checkIfIpInRangesVec(values, subject_ip.unpack());
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Destination ip adderss didn't match";
|
||||
return false;
|
||||
}
|
||||
|
||||
SourcePortMatcher::SourcePortMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<PortNumber>> port_range = CustomRange<PortNumber>::createRange(param);
|
||||
if (!port_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create source port.";
|
||||
continue;
|
||||
}
|
||||
values.push_back(port_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
SourcePortMatcher::evalVariable() const
|
||||
{
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Source is not a match";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ListeningPortMatcher::ListeningPortMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<PortNumber>> port_range = CustomRange<PortNumber>::createRange(param);
|
||||
if (!port_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create listening port range.";
|
||||
continue;
|
||||
}
|
||||
values.push_back(port_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
ListeningPortMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<ListeningPortMatcher>();
|
||||
auto port_str = env->get<string>(Context::MetaDataType::Port);
|
||||
if (!port_str.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get port from the enviroment.";
|
||||
return false;
|
||||
}
|
||||
PortNumber port;
|
||||
if (ConnKeyUtil::fromString(port_str.unpack(), port)) {
|
||||
if (values.size() == 0) return true;
|
||||
for (const CustomRange<PortNumber> &port_range : values) {
|
||||
if (port_range.contains(port)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Listening port is a match. Value: " << port_str.unpack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Listening port is not a match. Value: " << port_str.unpack();
|
||||
return false;
|
||||
}
|
||||
|
||||
IpProtocolMatcher::IpProtocolMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
for (const string ¶m : params) {
|
||||
Maybe<CustomRange<IPProto>> proto_range = CustomRange<IPProto>::createRange(param);
|
||||
if (!proto_range.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to create ip protocol.";
|
||||
continue;
|
||||
}
|
||||
values.push_back(proto_range.unpack());
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
IpProtocolMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<IpProtocolMatcher>();
|
||||
auto proto_str = env->get<string>(Context::MetaDataType::Protocol);
|
||||
if (!proto_str.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get ip protocol from the enviroment.";
|
||||
return false;
|
||||
}
|
||||
IPProto protocol;
|
||||
if (ConnKeyUtil::fromString(proto_str.unpack(), protocol)) {
|
||||
if (values.size() == 0) return true;
|
||||
for (const CustomRange<IPProto> &proto_range : values) {
|
||||
if (proto_range.contains(protocol)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Ip protocol is a match. Value: " << proto_str.unpack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Source port is not a match. Value: " << proto_str.unpack();
|
||||
return false;
|
||||
}
|
||||
|
||||
UrlMatcher::UrlMatcher(const vector<string> ¶ms) : values(params) {}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
UrlMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<UrlMatcher>();
|
||||
auto curr_url_ctx = env->get<string>(Context::MetaDataType::Url);
|
||||
if (!curr_url_ctx.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to get URL from the enviroment.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (values.size() == 0) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Matched URL on \"any\". Url: " << *curr_url_ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const string &url : values) {
|
||||
if (*curr_url_ctx == url) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Matched URL. Value: " << *curr_url_ctx;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "URL is not a match. Value: " << *curr_url_ctx;
|
||||
return false;
|
||||
}
|
||||
125
components/generic_rulebase/evaluators/http_transaction_data_eval.cc
Executable file
125
components/generic_rulebase/evaluators/http_transaction_data_eval.cc
Executable file
@@ -0,0 +1,125 @@
|
||||
// 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 "sasal.h"
|
||||
|
||||
SASAL_START // HTTP Manager - Transaction data
|
||||
|
||||
using namespace std;
|
||||
using namespace EnvironmentHelper;
|
||||
|
||||
EqualHost::EqualHost(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("EqualHost", params.size(), 1, 1);
|
||||
host = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
EqualHost::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<EqualHost>();
|
||||
auto host_ctx = env->get<string>(HttpTransactionData::host_name_ctx);
|
||||
|
||||
if (!host_ctx.ok())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string lower_host_ctx = host_ctx.unpack();
|
||||
std::transform(lower_host_ctx.begin(), lower_host_ctx.end(), lower_host_ctx.begin(), ::tolower);
|
||||
|
||||
std::string lower_host = host;
|
||||
std::transform(lower_host.begin(), lower_host.end(), lower_host.begin(), ::tolower);
|
||||
|
||||
|
||||
if (lower_host_ctx == lower_host) return true;
|
||||
size_t pos = lower_host_ctx.find_last_of(':');
|
||||
if (pos == string::npos) return false;
|
||||
lower_host_ctx = string(lower_host_ctx.data(), pos);
|
||||
return lower_host_ctx == lower_host;
|
||||
}
|
||||
|
||||
EqualListeningIP::EqualListeningIP(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("EqualListeningIP", params.size(), 1, 1);
|
||||
|
||||
auto maybe_ip = IPAddr::createIPAddr(params[0]);
|
||||
if (!maybe_ip.ok()) reportWrongParamType(getName(), params[0], "Not a valid IP Address");
|
||||
|
||||
listening_ip = maybe_ip.unpack();
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
EqualListeningIP::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<EqualListeningIP>();
|
||||
auto listening_ip_ctx = env->get<IPAddr>(HttpTransactionData::listening_ip_ctx);
|
||||
return listening_ip_ctx.ok() && listening_ip_ctx.unpack() == listening_ip;
|
||||
}
|
||||
|
||||
EqualListeningPort::EqualListeningPort(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("EqualListeningPort", params.size(), 1, 1);
|
||||
|
||||
try {
|
||||
listening_port = boost::lexical_cast<PortNumber>(params[0]);
|
||||
} catch (boost::bad_lexical_cast const&) {
|
||||
reportWrongParamType(getName(), params[0], "Not a valid port number");
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
EqualListeningPort::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<EqualListeningPort>();
|
||||
auto port_ctx = env->get<PortNumber>(HttpTransactionData::listening_port_ctx);
|
||||
|
||||
return port_ctx.ok() && port_ctx.unpack() == listening_port;
|
||||
}
|
||||
|
||||
BeginWithUri::BeginWithUri(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams("BeginWithUri", params.size(), 1, 1);
|
||||
uri_prefix = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
BeginWithUri::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<BeginWithUri>();
|
||||
auto uri_ctx = env->get<string>(HttpTransactionData::uri_ctx);
|
||||
|
||||
if (!uri_ctx.ok())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string lower_uri_ctx = uri_ctx.unpack();
|
||||
std::transform(lower_uri_ctx.begin(), lower_uri_ctx.end(), lower_uri_ctx.begin(), ::tolower);
|
||||
|
||||
std::string lower_uri_prefix = uri_prefix;
|
||||
std::transform(lower_uri_prefix.begin(), lower_uri_prefix.end(), lower_uri_prefix.begin(), ::tolower);
|
||||
|
||||
return lower_uri_ctx.find(lower_uri_prefix) == 0;
|
||||
}
|
||||
|
||||
SASAL_END
|
||||
38
components/generic_rulebase/evaluators/parameter_eval.cc
Executable file
38
components/generic_rulebase/evaluators/parameter_eval.cc
Executable file
@@ -0,0 +1,38 @@
|
||||
// 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> ¶ms)
|
||||
{
|
||||
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);
|
||||
}
|
||||
50
components/generic_rulebase/evaluators/practice_eval.cc
Executable file
50
components/generic_rulebase/evaluators/practice_eval.cc
Executable file
@@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "generic_rulebase/evaluators/practice_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
string PracticeMatcher::ctx_key = "practices";
|
||||
|
||||
PracticeMatcher::PracticeMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(PracticeMatcher::getName(), params.size(), 1, 1);
|
||||
practice_id = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
PracticeMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<PracticeMatcher>();
|
||||
auto bc_practice_id_ctx = env->get<set<GenericConfigId>>(PracticeMatcher::ctx_key);
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Trying to match practice. ID: "
|
||||
<< practice_id << ", Current set IDs: "
|
||||
<< makeSeparatedStr(bc_practice_id_ctx.ok() ? *bc_practice_id_ctx : set<GenericConfigId>(), ", ");
|
||||
if (bc_practice_id_ctx.ok()) {
|
||||
return bc_practice_id_ctx.unpack().count(practice_id) > 0;
|
||||
}
|
||||
|
||||
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
|
||||
return rule.ok() && rule.unpack().isPracticeActive(practice_id);
|
||||
}
|
||||
136
components/generic_rulebase/evaluators/query_eval.cc
Executable file
136
components/generic_rulebase/evaluators/query_eval.cc
Executable file
@@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "generic_rulebase/evaluators/query_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "generic_rulebase/zones_config.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "enum_range.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
QueryMatcher::QueryMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() < 1) reportWrongNumberOfParams(QueryMatcher::getName(), params.size(), 1);
|
||||
|
||||
key = params.front();
|
||||
if (key == "any") {
|
||||
is_any = true;
|
||||
} else {
|
||||
values.reserve(params.size() - 1);
|
||||
for (uint i = 1; i < params.size() ; i++) {
|
||||
if (params[i] == "any") {
|
||||
values.clear();
|
||||
break;
|
||||
}
|
||||
values.insert(params[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const string
|
||||
QueryMatcher::contextKeyToString(Context::MetaDataType type)
|
||||
{
|
||||
if (type == Context::MetaDataType::SubjectIpAddr || type == Context::MetaDataType::OtherIpAddr) return "ip";
|
||||
return Context::convertToString(type);
|
||||
}
|
||||
|
||||
class QueryMatchSerializer
|
||||
{
|
||||
public:
|
||||
static const string req_attr_ctx_key;
|
||||
|
||||
template <typename Archive>
|
||||
void
|
||||
serialize(Archive &ar)
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<QueryMatcher>();
|
||||
auto req_attr = env->get<string>(req_attr_ctx_key);
|
||||
if (!req_attr.ok()) return;
|
||||
|
||||
try {
|
||||
ar(cereal::make_nvp(*req_attr, value));
|
||||
dbgDebug(D_RULEBASE_CONFIG)
|
||||
<< "Found value for requested attribute. Tag: "
|
||||
<< *req_attr
|
||||
<< ", Value: "
|
||||
<< value;
|
||||
} catch (exception &e) {
|
||||
dbgDebug(D_RULEBASE_CONFIG) << "Could not find values for requested attribute. Tag: " << *req_attr;
|
||||
ar.finishNode();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Values>
|
||||
bool
|
||||
matchValues(const Values &requested_vals) const
|
||||
{
|
||||
return value != "" && (requested_vals.empty() || requested_vals.count(value) > 0);
|
||||
}
|
||||
|
||||
private:
|
||||
string value;
|
||||
};
|
||||
|
||||
const string QueryMatchSerializer::req_attr_ctx_key = "requested attribute key";
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
QueryMatcher::evalVariable() const
|
||||
{
|
||||
if (is_any) return true;
|
||||
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<QueryMatcher>();
|
||||
auto local_asset_ctx = env->get<bool>("is local asset");
|
||||
bool is_remote_asset = local_asset_ctx.ok() && !(*local_asset_ctx);
|
||||
|
||||
QueryRequest request;
|
||||
for (Context::MetaDataType name : makeRange<Context::MetaDataType>()) {
|
||||
auto val = env->get<string>(name);
|
||||
if (val.ok()) {
|
||||
if ((name == Context::MetaDataType::SubjectIpAddr && is_remote_asset) ||
|
||||
(name == Context::MetaDataType::OtherIpAddr && !is_remote_asset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
request.addCondition(Condition::EQUALS, contextKeyToString(name), *val);
|
||||
}
|
||||
}
|
||||
if (request.empty()) return false;
|
||||
|
||||
request.setRequestedAttr(key);
|
||||
ScopedContext req_attr_key;
|
||||
req_attr_key.registerValue<string>(QueryMatchSerializer::req_attr_ctx_key, key);
|
||||
|
||||
I_Intelligence_IS_V2 *intelligence = Singleton::Consume<I_Intelligence_IS_V2>::by<Zone>();
|
||||
auto query_res = intelligence->queryIntelligence<QueryMatchSerializer>(request);
|
||||
if (!query_res.ok()) {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Failed to perform intelligence query. Error: " << query_res.getErr();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const AssetReply<QueryMatchSerializer> &asset : query_res.unpack()) {
|
||||
if (asset.matchValues<unordered_set<string>>(values)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
57
components/generic_rulebase/evaluators/trigger_eval.cc
Executable file
57
components/generic_rulebase/evaluators/trigger_eval.cc
Executable file
@@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "generic_rulebase/evaluators/trigger_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
string TriggerMatcher::ctx_key = "triggers";
|
||||
|
||||
TriggerMatcher::TriggerMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(TriggerMatcher::getName(), params.size(), 1, 1);
|
||||
trigger_id = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
TriggerMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<TriggerMatcher>();
|
||||
auto ac_bc_trigger_id_ctx = env->get<set<GenericConfigId>>("ac_trigger_id");
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Trying to match trigger for access control rule. ID: "
|
||||
<< trigger_id << ", Current set IDs: "
|
||||
<< makeSeparatedStr(ac_bc_trigger_id_ctx.ok() ? *ac_bc_trigger_id_ctx : set<GenericConfigId>(), ", ");
|
||||
if (ac_bc_trigger_id_ctx.ok()) {
|
||||
return ac_bc_trigger_id_ctx.unpack().count(trigger_id) > 0;
|
||||
}
|
||||
|
||||
auto bc_trigger_id_ctx = env->get<set<GenericConfigId>>(TriggerMatcher::ctx_key);
|
||||
dbgTrace(D_RULEBASE_CONFIG)
|
||||
<< "Trying to match trigger. ID: "
|
||||
<< trigger_id << ", Current set IDs: "
|
||||
<< makeSeparatedStr(bc_trigger_id_ctx.ok() ? *bc_trigger_id_ctx : set<GenericConfigId>(), ", ");
|
||||
if (bc_trigger_id_ctx.ok() && bc_trigger_id_ctx.unpack().count(trigger_id) > 0 ) return true;
|
||||
|
||||
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
|
||||
return rule.ok() && rule.unpack().isTriggerActive(trigger_id);
|
||||
}
|
||||
44
components/generic_rulebase/evaluators/zone_eval.cc
Executable file
44
components/generic_rulebase/evaluators/zone_eval.cc
Executable file
@@ -0,0 +1,44 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "generic_rulebase/evaluators/zone_eval.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "generic_rulebase/zone.h"
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
#include "config.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string ZoneMatcher::ctx_key = "zone_id";
|
||||
|
||||
ZoneMatcher::ZoneMatcher(const vector<string> ¶ms)
|
||||
{
|
||||
if (params.size() != 1) reportWrongNumberOfParams(ZoneMatcher::getName(), params.size(), 1, 1);
|
||||
zone_id = params[0];
|
||||
}
|
||||
|
||||
Maybe<bool, Context::Error>
|
||||
ZoneMatcher::evalVariable() const
|
||||
{
|
||||
I_Environment *env = Singleton::Consume<I_Environment>::by<ZoneMatcher>();
|
||||
auto bc_zone_id_ctx = env->get<GenericConfigId>(ZoneMatcher::ctx_key);
|
||||
if (bc_zone_id_ctx.ok() && *bc_zone_id_ctx == zone_id) return true;
|
||||
|
||||
if (!getProfileAgentSettingWithDefault<bool>(false, "rulebase.enableQueryBasedMatch")) return false;
|
||||
|
||||
auto zone = getConfiguration<Zone>("rulebase", "zones");
|
||||
return zone.ok() && zone.unpack().getId() == zone_id;
|
||||
}
|
||||
125
components/generic_rulebase/generic_rulebase.cc
Executable file
125
components/generic_rulebase/generic_rulebase.cc
Executable file
@@ -0,0 +1,125 @@
|
||||
// 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<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();
|
||||
}
|
||||
109
components/generic_rulebase/generic_rulebase_context.cc
Executable file
109
components/generic_rulebase/generic_rulebase_context.cc
Executable file
@@ -0,0 +1,109 @@
|
||||
// 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
291
components/generic_rulebase/match_query.cc
Executable file
291
components/generic_rulebase/match_query.cc
Executable file
@@ -0,0 +1,291 @@
|
||||
// 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 }
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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) 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);
|
||||
} else if (type == MatchType::Operator && operator_type == Operators::And) {
|
||||
for (const MatchQuery &inner_match: items) {
|
||||
if (!inner_match.matchAttributes(key_value_pairs)) return false;
|
||||
}
|
||||
return true;
|
||||
} else if (type == MatchType::Operator && operator_type == Operators::Or) {
|
||||
for (const MatchQuery &inner_match: items) {
|
||||
if (inner_match.matchAttributes(key_value_pairs)) return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
dbgWarning(D_RULEBASE_CONFIG) << "Unsupported match query type";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributes(const set<string> &values) const
|
||||
{
|
||||
auto &type = condition_type;
|
||||
bool negate = type == MatchQuery::Conditions::NotEquals || type == MatchQuery::Conditions::NotIn;
|
||||
bool match = isRegEx() ? matchAttributesRegEx(values) : matchAttributesString(values);
|
||||
return negate ? !match : match;
|
||||
}
|
||||
|
||||
bool
|
||||
MatchQuery::matchAttributesRegEx(const set<string> &values) const
|
||||
{
|
||||
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))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
126
components/generic_rulebase/parameters_config.cc
Executable file
126
components/generic_rulebase/parameters_config.cc
Executable file
@@ -0,0 +1,126 @@
|
||||
// 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) const
|
||||
{
|
||||
set<ParameterBehavior> matched_behaviors;
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Matching exception";
|
||||
for (const MatchBehaviorPair &match_behavior_pair: match_queries) {
|
||||
if (match_behavior_pair.match.matchAttributes(key_value_pairs)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception from a list of matches.";
|
||||
matched_behaviors.insert(match_behavior_pair.behavior);
|
||||
}
|
||||
}
|
||||
if (match_queries.empty() && match.matchAttributes(key_value_pairs)) {
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
|
||||
matched_behaviors.insert(behavior);
|
||||
}
|
||||
return matched_behaviors;
|
||||
}
|
||||
79
components/generic_rulebase/rulebase_config.cc
Executable file
79
components/generic_rulebase/rulebase_config.cc
Executable file
@@ -0,0 +1,79 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "generic_rulebase/rulebase_config.h"
|
||||
|
||||
#include "telemetry.h"
|
||||
#include "config.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
using namespace std;
|
||||
|
||||
set<string> BasicRuleConfig::assets_ids{};
|
||||
set<string> BasicRuleConfig::assets_ids_aggregation{};
|
||||
|
||||
void
|
||||
BasicRuleConfig::load(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
parseJSONKey<vector<RulePractice>>("practices", practices, ar);
|
||||
parseJSONKey<vector<RuleTrigger>>("triggers", triggers, ar);
|
||||
parseJSONKey<vector<RuleParameter>>("parameters", parameters, ar);
|
||||
parseJSONKey<uint8_t>("priority", priority, ar);
|
||||
parseJSONKey<string>("ruleId", rule_id, ar);
|
||||
parseJSONKey<string>("ruleName", rule_name, ar);
|
||||
parseJSONKey<string>("assetId", asset_id, ar);
|
||||
parseJSONKey<string>("assetName", asset_name, ar);
|
||||
parseJSONKey<string>("zoneId", zone_id, ar);
|
||||
parseJSONKey<string>("zoneName", zone_name, ar);
|
||||
|
||||
assets_ids_aggregation.insert(asset_id);
|
||||
}
|
||||
|
||||
void
|
||||
BasicRuleConfig::updateCountMetric()
|
||||
{
|
||||
BasicRuleConfig::assets_ids = BasicRuleConfig::assets_ids_aggregation;
|
||||
AssetCountEvent(AssetType::ALL, BasicRuleConfig::assets_ids.size()).notify();
|
||||
}
|
||||
|
||||
bool
|
||||
BasicRuleConfig::isPracticeActive(const string &practice_id) const
|
||||
{
|
||||
for (auto practice: practices) {
|
||||
if (practice.getId() == practice_id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BasicRuleConfig::isTriggerActive(const string &trigger_id) const
|
||||
{
|
||||
for (auto trigger: triggers) {
|
||||
if (trigger.getId() == trigger_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BasicRuleConfig::isParameterActive(const string ¶meter_id) const
|
||||
{
|
||||
for (auto param: parameters) {
|
||||
if (param.getId() == parameter_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
216
components/generic_rulebase/triggers_config.cc
Executable file
216
components/generic_rulebase/triggers_config.cc
Executable file
@@ -0,0 +1,216 @@
|
||||
// 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 = "")
|
||||
{
|
||||
dbgTrace(D_RULEBASE_CONFIG) << "log server url:" << log_server_url;
|
||||
if (log_server_url != "") {
|
||||
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type, log_server_url);
|
||||
} else {
|
||||
Singleton::Consume<I_Logging>::by<LogTriggerConf>()->addStream(log_type);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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("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::SYSLOG:
|
||||
setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog());
|
||||
break;
|
||||
case ReportIS::StreamType::CEF:
|
||||
setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef());
|
||||
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);
|
||||
}
|
||||
}
|
||||
179
components/generic_rulebase/zone.cc
Executable file
179
components/generic_rulebase/zone.cc
Executable file
@@ -0,0 +1,179 @@
|
||||
// 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 pair<Context::MetaDataType, string> &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;
|
||||
}
|
||||
114
components/generic_rulebase/zones_config.cc
Executable file
114
components/generic_rulebase/zones_config.cc
Executable file
@@ -0,0 +1,114 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
dbgWarning(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()) {
|
||||
dbgWarning(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");
|
||||
}
|
||||
7
components/gradual_deployment/CMakeLists.txt
Normal file
7
components/gradual_deployment/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
add_definitions(-DUSERSPACE)
|
||||
|
||||
include_directories(include)
|
||||
|
||||
add_library(gradual_deployment gradual_deployment.cc )
|
||||
|
||||
add_subdirectory(gradual_deployment_ut)
|
||||
227
components/gradual_deployment/gradual_deployment.cc
Normal file
227
components/gradual_deployment/gradual_deployment.cc
Normal file
@@ -0,0 +1,227 @@
|
||||
// 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 "gradual_deployment.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "enum_range.h"
|
||||
#include "connkey.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_GRADUAL_DEPLOYMENT);
|
||||
|
||||
using namespace std;
|
||||
|
||||
class SetGradualDeploymentRanges : public ServerRest
|
||||
{
|
||||
public:
|
||||
void doCall() override
|
||||
{
|
||||
dbgFlow(D_GRADUAL_DEPLOYMENT) << "Set gradual policy API";
|
||||
|
||||
auto maybe_type = convertServiceStrToAttachmentType(attachment_type.get());
|
||||
if (!maybe_type.ok()) {
|
||||
string error = "Failed to determine attachment type. Type: "
|
||||
+ attachment_type.get()
|
||||
+ ", error: "
|
||||
+ maybe_type.getErr();
|
||||
dbgWarning(D_GRADUAL_DEPLOYMENT) << error;
|
||||
throw JsonError(error);
|
||||
}
|
||||
dbgTrace(D_GRADUAL_DEPLOYMENT)
|
||||
<< "Setting gradual policy for attachment of type: "
|
||||
<< attachment_type.get();
|
||||
|
||||
auto i_gradual_deployment = Singleton::Consume<I_GradualDeployment>::from<GradualDeployment>();
|
||||
auto set_policy_res = i_gradual_deployment->setPolicy(maybe_type.unpackMove(), ip_ranges.get());
|
||||
if (!set_policy_res.ok()) throw JsonError(set_policy_res.getErr());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private:
|
||||
C2S_PARAM(vector<string>, ip_ranges)
|
||||
C2S_PARAM(string, attachment_type)
|
||||
|
||||
Maybe<I_GradualDeployment::AttachmentType>
|
||||
convertServiceStrToAttachmentType(string &type) {
|
||||
transform(type.begin(), type.end(), type.begin(), ::tolower);
|
||||
if (type == "http-manager") return I_GradualDeployment::AttachmentType::NGINX;
|
||||
if (type == "access-control") return I_GradualDeployment::AttachmentType::KERNEL;
|
||||
|
||||
return genError("unknown attachment type");
|
||||
}
|
||||
};
|
||||
|
||||
class GradualDeployment::Impl
|
||||
:
|
||||
Singleton::Provide<I_GradualDeployment>::From<GradualDeployment>
|
||||
{
|
||||
public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
dbgFlow(D_GRADUAL_DEPLOYMENT) << "Initializing Gradual Deployment Manager";
|
||||
|
||||
auto rest = Singleton::Consume<I_RestApi>::by<GradualDeployment>();
|
||||
rest->addRestCall<SetGradualDeploymentRanges>(RestAction::SET, "gradual-deployment-policy");
|
||||
|
||||
dbgTrace(D_GRADUAL_DEPLOYMENT) << "Gradual Deployment Manager initialization is done successfully";
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
setPolicy(I_GradualDeployment::AttachmentType type, const vector<string> &str_ip_ranges) override
|
||||
{
|
||||
auto maybe_policy = parseIpRanges(str_ip_ranges);
|
||||
if (!maybe_policy.ok()) {
|
||||
auto error = "Failed to set gradual deployment policy. Error: " + maybe_policy.getErr();
|
||||
dbgWarning(D_GRADUAL_DEPLOYMENT) << error;
|
||||
return genError(error);
|
||||
}
|
||||
|
||||
ip_ranges_map[static_cast<int>(type)] = maybe_policy.unpackMove();
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
vector<string>
|
||||
getPolicy(I_GradualDeployment::AttachmentType type) override
|
||||
{
|
||||
vector<string> res;
|
||||
for (const IPRange &range : ip_ranges_map[static_cast<int>(type)]) {
|
||||
// Range is validated on insertion
|
||||
res.push_back(convertIpRangeToStr(range).unpack());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
vector<IPRange> &
|
||||
getParsedPolicy(I_GradualDeployment::AttachmentType type) override
|
||||
{
|
||||
return ip_ranges_map[static_cast<int>(type)];
|
||||
}
|
||||
|
||||
private:
|
||||
IpAddress
|
||||
ConvertToIpAddress(const IPAddr &addr) {
|
||||
IpAddress address;
|
||||
switch (addr.getType()) {
|
||||
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:
|
||||
dbgAssert(false) << "Unsupported IP type";
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
Maybe<IPRange>
|
||||
createRangeFromStr(const string &range)
|
||||
{
|
||||
vector<string> temp_params_list;
|
||||
boost::split(temp_params_list, range, boost::is_any_of("-"));
|
||||
|
||||
if (temp_params_list.size() == 1) {
|
||||
Maybe<IPAddr> maybe_ip = IPAddr::createIPAddr(temp_params_list[0]);
|
||||
if (!maybe_ip.ok()) return genError("Could not create IP address, " + maybe_ip.getErr());
|
||||
IpAddress addr = move(ConvertToIpAddress(maybe_ip.unpackMove()));
|
||||
|
||||
return move(IPRange{.start = addr, .end = addr});
|
||||
}
|
||||
|
||||
if (temp_params_list.size() == 2) {
|
||||
Maybe<IPAddr> maybe_ip_min = IPAddr::createIPAddr(temp_params_list[0]);
|
||||
Maybe<IPAddr> maybe_ip_max = IPAddr::createIPAddr(temp_params_list[1]);
|
||||
if (!maybe_ip_min.ok()) return genError("Could not create IP address, " + maybe_ip_min.getErr());
|
||||
if (!maybe_ip_max.ok()) return genError("Could not create IP address, " + maybe_ip_max.getErr());
|
||||
|
||||
IPAddr min_addr = maybe_ip_min.unpackMove();
|
||||
IPAddr max_addr = maybe_ip_max.unpackMove();
|
||||
if (min_addr > max_addr) return genError("Could not create ip range - start greater then end");
|
||||
|
||||
IpAddress addr_min = move(ConvertToIpAddress(move(min_addr)));
|
||||
IpAddress addr_max = move(ConvertToIpAddress(move(max_addr)));
|
||||
if (addr_max.ip_type != addr_min.ip_type) return genError("Range IP's type does not match");
|
||||
|
||||
return move(IPRange{.start = move(addr_min), .end = move(addr_max)});
|
||||
}
|
||||
|
||||
return genError("Illegal range received: " + range);
|
||||
}
|
||||
|
||||
Maybe<vector<IPRange>>
|
||||
parseIpRanges(const vector<string> &str_ip_ranges)
|
||||
{
|
||||
vector<IPRange> ip_ranges;
|
||||
for (const string &range : str_ip_ranges) {
|
||||
Maybe<IPRange> ip_range = createRangeFromStr(range);
|
||||
if (!ip_range.ok()) {
|
||||
return genError("Failed to parse gradual deployment IP range: " + ip_range.getErr());
|
||||
}
|
||||
|
||||
ip_ranges.push_back(ip_range.unpackMove());
|
||||
}
|
||||
return move(ip_ranges);
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
convertIpRangeToStr(const IPRange &range)
|
||||
{
|
||||
if (range.start.ip_type != IP_VERSION_4 && range.start.ip_type != IP_VERSION_6) {
|
||||
return genError("Unknown IP type received: " + range.start.ip_type);
|
||||
}
|
||||
|
||||
size_t len;
|
||||
int type;
|
||||
const void *in_addr_min;
|
||||
const void *in_addr_max;
|
||||
|
||||
if (range.start.ip_type == IP_VERSION_4) {
|
||||
len = INET_ADDRSTRLEN;
|
||||
type = AF_INET;
|
||||
in_addr_min = &range.start.ip.ipv4;
|
||||
in_addr_max = &range.end.ip.ipv4;
|
||||
} else {
|
||||
len = INET6_ADDRSTRLEN;
|
||||
type = AF_INET6;
|
||||
in_addr_min = &range.start.ip.ipv6;
|
||||
in_addr_max = &range.end.ip.ipv6;
|
||||
}
|
||||
|
||||
char str_min[len];
|
||||
inet_ntop(type, in_addr_min, str_min, len);
|
||||
char str_max[len];
|
||||
inet_ntop(type, in_addr_max, str_max, len);
|
||||
|
||||
string start(str_min, strnlen(str_min, len));
|
||||
string end(str_max, strnlen(str_max, len));
|
||||
|
||||
return start + "-" + end;
|
||||
}
|
||||
|
||||
unordered_map<size_t, vector<IPRange>> ip_ranges_map;
|
||||
};
|
||||
|
||||
GradualDeployment::GradualDeployment() : Component("GradualDeployment"), pimpl(make_unique<Impl>()) {}
|
||||
|
||||
GradualDeployment::~GradualDeployment() {}
|
||||
|
||||
void GradualDeployment::init() { pimpl->init(); }
|
||||
@@ -0,0 +1,8 @@
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_SOURCE_DIR}/components/include)
|
||||
|
||||
add_unit_test(
|
||||
gradual_deployment_ut
|
||||
"gradual_deployment_ut.cc"
|
||||
"singleton;rest;connkey;${RT_LIBRARY};gradual_deployment;"
|
||||
)
|
||||
@@ -0,0 +1,127 @@
|
||||
#include "http_manager.h"
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
|
||||
#include "cptest.h"
|
||||
#include "config.h"
|
||||
#include "singleton.h"
|
||||
#include "environment.h"
|
||||
#include "rest_server.h"
|
||||
#include "table.h"
|
||||
#include "time_proxy.h"
|
||||
#include "mainloop.h"
|
||||
#include "mock/mock_rest_api.h"
|
||||
#include "i_http_manager.h"
|
||||
#include "gradual_deployment.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
class GradualDeploymentTest : public Test
|
||||
{
|
||||
public:
|
||||
GradualDeploymentTest()
|
||||
{
|
||||
EXPECT_CALL(rest, mockRestCall(RestAction::SET, "gradual-deployment-policy", _)).WillOnce(
|
||||
WithArg<2>(Invoke(this, &GradualDeploymentTest::setGDPolicy))
|
||||
);
|
||||
|
||||
gradual_deployment.init();
|
||||
i_gradual_deployment = Singleton::Consume<I_GradualDeployment>::from(gradual_deployment);
|
||||
}
|
||||
|
||||
bool
|
||||
setGDPolicy(const unique_ptr<RestInit> &p)
|
||||
{
|
||||
gradual_rest_listener = p->getRest();
|
||||
return true;
|
||||
}
|
||||
|
||||
unique_ptr<ServerRest> gradual_rest_listener;
|
||||
I_GradualDeployment *i_gradual_deployment;
|
||||
|
||||
private:
|
||||
StrictMock<MockRestApi> rest;
|
||||
GradualDeployment gradual_deployment;
|
||||
};
|
||||
|
||||
TEST_F(GradualDeploymentTest, getPolicyTest)
|
||||
{
|
||||
stringstream is;
|
||||
is << "{"
|
||||
<< "\"attachment_type\":\"HTTP-Manager\","
|
||||
<< "\"ip_ranges\":[\"8.8.8.8\",\"9.9.9.9-10.10.10.10\","
|
||||
<< "\"0:0:0:0:0:0:0:1-0:0:0:0:0:0:0:4\""
|
||||
<< "]}";
|
||||
Maybe<string> rest_call_result = gradual_rest_listener->performRestCall(is);
|
||||
EXPECT_TRUE(rest_call_result.ok());
|
||||
|
||||
vector<string> expected = {"8.8.8.8-8.8.8.8", "9.9.9.9-10.10.10.10", "::1-::4"};
|
||||
vector<string> curr_policy = i_gradual_deployment->getPolicy(I_GradualDeployment::AttachmentType::NGINX);
|
||||
EXPECT_EQ(curr_policy, expected);
|
||||
}
|
||||
|
||||
TEST_F(GradualDeploymentTest, MissingAttachmentType)
|
||||
{
|
||||
stringstream is("{\"ip_ranges\":[\"8.8\"]}");
|
||||
Maybe<string> rest_call_result = gradual_rest_listener->performRestCall(is);
|
||||
EXPECT_FALSE(rest_call_result.ok());
|
||||
EXPECT_THAT(
|
||||
rest_call_result.getErr(),
|
||||
HasSubstr("Couldn't get variable attachment_type")
|
||||
);
|
||||
|
||||
vector<string> expected = {};
|
||||
vector<string> curr_policy = i_gradual_deployment->getPolicy(I_GradualDeployment::AttachmentType::NGINX);
|
||||
EXPECT_EQ(curr_policy, expected);
|
||||
}
|
||||
|
||||
TEST_F(GradualDeploymentTest, InvalidAttachmentType)
|
||||
{
|
||||
stringstream is;
|
||||
is << "{"
|
||||
<< "\"attachment_type\":\"unsupported-attachment-type\","
|
||||
<< "\"ip_ranges\":[\"8.8.8.8\",\"9.9.9.9-10.10.10.10\","
|
||||
<< "\"0:0:0:0:0:0:0:1-0:0:0:0:0:0:0:4\""
|
||||
<< "]}";
|
||||
Maybe<string> rest_call_result = gradual_rest_listener->performRestCall(is);
|
||||
EXPECT_FALSE(rest_call_result.ok());
|
||||
EXPECT_THAT(
|
||||
rest_call_result.getErr(),
|
||||
HasSubstr(
|
||||
"Failed to determine attachment type. "
|
||||
"Type: unsupported-attachment-type, error: unknown attachment type"
|
||||
)
|
||||
);
|
||||
|
||||
vector<string> expected = {};
|
||||
vector<string> curr_policy = i_gradual_deployment->getPolicy(I_GradualDeployment::AttachmentType::NGINX);
|
||||
EXPECT_EQ(curr_policy, expected);
|
||||
}
|
||||
|
||||
TEST_F(GradualDeploymentTest, InvalidIPRanges)
|
||||
{
|
||||
stringstream is;
|
||||
is << "{"
|
||||
<< "\"attachment_type\":\"HTTP-Manager\","
|
||||
<< "\"ip_ranges\":[\"8.8\"]"
|
||||
<< "}";
|
||||
|
||||
Maybe<string> rest_call_result = gradual_rest_listener->performRestCall(is);
|
||||
EXPECT_FALSE(rest_call_result.ok());
|
||||
EXPECT_THAT(
|
||||
rest_call_result.getErr(),
|
||||
HasSubstr(
|
||||
"Failed to set gradual deployment policy. "
|
||||
"Error: Failed to parse gradual deployment IP range: "
|
||||
"Could not create IP address, String '8.8' is not a valid IPv4/IPv6 address"
|
||||
)
|
||||
);
|
||||
|
||||
vector<string> expected = {};
|
||||
vector<string> curr_policy = i_gradual_deployment->getPolicy(I_GradualDeployment::AttachmentType::NGINX);
|
||||
|
||||
EXPECT_EQ(curr_policy, expected);
|
||||
}
|
||||
3
components/health_check_manager/CMakeLists.txt
Executable file
3
components/health_check_manager/CMakeLists.txt
Executable file
@@ -0,0 +1,3 @@
|
||||
add_library(health_check_manager health_check_manager.cc)
|
||||
|
||||
add_subdirectory(health_check_manager_ut)
|
||||
250
components/health_check_manager/health_check_manager.cc
Executable file
250
components/health_check_manager/health_check_manager.cc
Executable file
@@ -0,0 +1,250 @@
|
||||
// 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 "health_check_manager.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
#include "health_check_status/health_check_status.h"
|
||||
#include "i_rest_api.h"
|
||||
#include "config.h"
|
||||
#include "cereal/archives/json.hpp"
|
||||
#include "customized_cereal_map.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_HEALTH_CHECK_MANAGER);
|
||||
|
||||
class HealthCheckOnDemand : public ServerRest, Singleton::Consume<I_Health_Check_Manager>
|
||||
{
|
||||
public:
|
||||
void
|
||||
doCall() override
|
||||
{
|
||||
string output_path = getProfileAgentSettingWithDefault<string>(
|
||||
"/tmp/cpnano_health_check_output.txt",
|
||||
"agent.healthCheck.outputTmpFilePath"
|
||||
);
|
||||
ofstream health_check_output_file;
|
||||
health_check_output_file.open(output_path, ofstream::out | ofstream::trunc);
|
||||
|
||||
auto manager = Singleton::Consume<I_Health_Check_Manager>::by<HealthCheckOnDemand>();
|
||||
manager->printRepliesHealthStatus(health_check_output_file);
|
||||
|
||||
health_check_output_file.close();
|
||||
}
|
||||
};
|
||||
|
||||
class HealthCheckError
|
||||
{
|
||||
public:
|
||||
HealthCheckError(const string &comp_name, const string &error)
|
||||
:
|
||||
code_name(comp_name),
|
||||
is_internal(true)
|
||||
{
|
||||
message.push_back(error);
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void
|
||||
serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
cereal::make_nvp("code", code_name),
|
||||
cereal::make_nvp("message", message),
|
||||
cereal::make_nvp("internal", is_internal)
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
string code_name;
|
||||
bool is_internal;
|
||||
vector<string> message;
|
||||
};
|
||||
|
||||
class HealthCheckValue
|
||||
{
|
||||
public:
|
||||
HealthCheckValue() = default;
|
||||
|
||||
HealthCheckValue(HealthCheckStatus raw_status, const map<string, HealthCheckStatusReply> &descriptions)
|
||||
:
|
||||
status(raw_status)
|
||||
{
|
||||
for (const pair<string, HealthCheckStatusReply> &single_stat : descriptions) {
|
||||
if (single_stat.second.getStatus() == HealthCheckStatus::HEALTHY) {
|
||||
dbgTrace(D_HEALTH_CHECK_MANAGER) << "Ignoring healthy status reply. Comp name: " << single_stat.first;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const pair<string, string> &status : single_stat.second.getExtendedStatus()) {
|
||||
errors.push_back(HealthCheckError(single_stat.first + " " + status.first, status.second));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void
|
||||
serialize(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
cereal::make_nvp("status", HealthCheckStatusReply::convertHealthCheckStatusToStr(status)),
|
||||
cereal::make_nvp("errors", errors)
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
HealthCheckStatus status = HealthCheckStatus::IGNORED;
|
||||
vector<HealthCheckError> errors;
|
||||
};
|
||||
|
||||
class HealthCheckPatch : public ClientRest
|
||||
{
|
||||
public:
|
||||
HealthCheckPatch(HealthCheckStatus raw_status, const map<string, HealthCheckStatusReply> &descriptions)
|
||||
{
|
||||
health_check = HealthCheckValue(raw_status, descriptions);
|
||||
}
|
||||
|
||||
C2S_LABEL_PARAM(HealthCheckValue, health_check, "healthCheck");
|
||||
};
|
||||
|
||||
class HealthCheckManager::Impl
|
||||
:
|
||||
Singleton::Provide<I_Health_Check_Manager>::From<HealthCheckManager>
|
||||
{
|
||||
public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
auto rest = Singleton::Consume<I_RestApi>::by<HealthCheckManager>();
|
||||
rest->addRestCall<HealthCheckOnDemand>(RestAction::SHOW, "health-check-on-demand");
|
||||
|
||||
int interval_in_seconds =
|
||||
getProfileAgentSettingWithDefault<int>(30, "agent.healthCheck.intervalInSeconds");
|
||||
|
||||
auto i_mainloop = Singleton::Consume<I_MainLoop>::by<HealthCheckManager>();
|
||||
i_mainloop->addRecurringRoutine(
|
||||
I_MainLoop::RoutineType::System,
|
||||
chrono::seconds(interval_in_seconds),
|
||||
[this]() { executeHealthCheck(); },
|
||||
"Health check manager periodic check"
|
||||
);
|
||||
|
||||
auto is_orch = Singleton::Consume<I_Environment>::by<HealthCheckManager>()->get<bool>("Is Orchestrator");
|
||||
should_patch_report = is_orch.ok() && *is_orch;
|
||||
}
|
||||
|
||||
HealthCheckStatus
|
||||
getAggregatedStatus()
|
||||
{
|
||||
executeHealthCheck();
|
||||
return general_health_aggregated_status;
|
||||
}
|
||||
|
||||
void
|
||||
printRepliesHealthStatus(ofstream &oputput_file)
|
||||
{
|
||||
getRegisteredComponentsHealthStatus();
|
||||
cereal::JSONOutputArchive ar(oputput_file);
|
||||
ar(cereal::make_nvp("allComponentsHealthCheckReplies", all_comps_health_status));
|
||||
}
|
||||
|
||||
private:
|
||||
bool
|
||||
sendHealthCheckPatch()
|
||||
{
|
||||
dbgFlow(D_HEALTH_CHECK_MANAGER);
|
||||
|
||||
HealthCheckPatch patch_to_send(general_health_aggregated_status, all_comps_health_status);
|
||||
auto messaging = Singleton::Consume<I_Messaging>::by<HealthCheckManager>();
|
||||
return messaging->sendNoReplyObject(patch_to_send, I_Messaging::Method::PATCH, "/agents");
|
||||
}
|
||||
|
||||
void
|
||||
getRegisteredComponentsHealthStatus()
|
||||
{
|
||||
vector<HealthCheckStatusReply> health_check_event_reply = HealthCheckStatusEvent().query();
|
||||
all_comps_health_status.clear();
|
||||
for (const auto &reply : health_check_event_reply) {
|
||||
if (reply.getStatus() != HealthCheckStatus::IGNORED) {
|
||||
all_comps_health_status.emplace(reply.getCompName(), reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
calcGeneralHealthAggregatedStatus()
|
||||
{
|
||||
general_health_aggregated_status = HealthCheckStatus::HEALTHY;
|
||||
|
||||
for (const pair<string, HealthCheckStatusReply> &reply : all_comps_health_status) {
|
||||
HealthCheckStatus status = reply.second.getStatus();
|
||||
|
||||
dbgTrace(D_HEALTH_CHECK_MANAGER)
|
||||
<< "Current aggregated status is: "
|
||||
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(
|
||||
general_health_aggregated_status
|
||||
)
|
||||
<< ". Got health status: "
|
||||
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(status)
|
||||
<< "for component: "
|
||||
<< reply.first;
|
||||
|
||||
switch (status) {
|
||||
case HealthCheckStatus::UNHEALTHY : {
|
||||
general_health_aggregated_status = HealthCheckStatus::UNHEALTHY;
|
||||
return;
|
||||
}
|
||||
case HealthCheckStatus::DEGRADED : {
|
||||
general_health_aggregated_status = HealthCheckStatus::DEGRADED;
|
||||
break;
|
||||
}
|
||||
case HealthCheckStatus::IGNORED : break;
|
||||
case HealthCheckStatus::HEALTHY : break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
executeHealthCheck()
|
||||
{
|
||||
dbgFlow(D_HEALTH_CHECK_MANAGER) << "Collecting health status from all registered components.";
|
||||
|
||||
getRegisteredComponentsHealthStatus();
|
||||
calcGeneralHealthAggregatedStatus();
|
||||
|
||||
dbgTrace(D_HEALTH_CHECK_MANAGER)
|
||||
<< "Aggregated status: "
|
||||
<< HealthCheckStatusReply::convertHealthCheckStatusToStr(general_health_aggregated_status);
|
||||
|
||||
if (!should_patch_report) return;
|
||||
|
||||
if (!sendHealthCheckPatch()) {
|
||||
dbgWarning(D_HEALTH_CHECK_MANAGER) << "Failed to send periodic health check patch to the fog";
|
||||
} else {
|
||||
dbgDebug(D_HEALTH_CHECK_MANAGER) << "Successfully sent periodic health check patch to the fog";
|
||||
};
|
||||
}
|
||||
|
||||
HealthCheckStatus general_health_aggregated_status;
|
||||
map<string, HealthCheckStatusReply> all_comps_health_status;
|
||||
bool should_patch_report;
|
||||
};
|
||||
|
||||
HealthCheckManager::HealthCheckManager() : Component("HealthCheckManager"), pimpl(make_unique<Impl>()) {}
|
||||
HealthCheckManager::~HealthCheckManager() {}
|
||||
|
||||
void HealthCheckManager::init() { pimpl->init(); }
|
||||
8
components/health_check_manager/health_check_manager_ut/CMakeLists.txt
Executable file
8
components/health_check_manager/health_check_manager_ut/CMakeLists.txt
Executable file
@@ -0,0 +1,8 @@
|
||||
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;mainloop;health_check_manager;event_is;metric;-lboost_regex"
|
||||
)
|
||||
@@ -0,0 +1,219 @@
|
||||
#include "health_check_manager.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
|
||||
#include "health_check_status/health_check_status.h"
|
||||
#include "environment.h"
|
||||
#include "config.h"
|
||||
#include "config_component.h"
|
||||
#include "cptest.h"
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_messaging.h"
|
||||
#include "mock/mock_rest_api.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
USE_DEBUG_FLAG(D_HEALTH_CHECK);
|
||||
|
||||
class TestHealthCheckStatusListener : public Listener<HealthCheckStatusEvent>
|
||||
{
|
||||
public:
|
||||
void upon(const HealthCheckStatusEvent &) override {}
|
||||
|
||||
HealthCheckStatusReply
|
||||
respond(const HealthCheckStatusEvent &) override
|
||||
{
|
||||
map<string, string> extended_status;
|
||||
extended_status["team"] = team;
|
||||
extended_status["city"] = city;
|
||||
HealthCheckStatusReply reply(comp_name, status, extended_status);
|
||||
return reply;
|
||||
}
|
||||
|
||||
void setStatus(HealthCheckStatus new_status) { status = new_status; }
|
||||
|
||||
string getListenerName() const { return "TestHealthCheckStatusListener"; }
|
||||
|
||||
private:
|
||||
static const string comp_name;
|
||||
HealthCheckStatus status = HealthCheckStatus::HEALTHY;
|
||||
static const string team;
|
||||
static const string city;
|
||||
};
|
||||
|
||||
const string TestHealthCheckStatusListener::comp_name = "Test";
|
||||
const string TestHealthCheckStatusListener::team = "Hapoel";
|
||||
const string TestHealthCheckStatusListener::city = "Tel-Aviv";
|
||||
|
||||
class TestEnd {};
|
||||
|
||||
class HealthCheckManagerTest : public Test
|
||||
{
|
||||
public:
|
||||
HealthCheckManagerTest()
|
||||
{
|
||||
Debug::setNewDefaultStdout(&debug_output);
|
||||
Debug::setUnitTestFlag(D_HEALTH_CHECK, Debug::DebugLevel::INFO);
|
||||
|
||||
EXPECT_CALL(mock_ml, addRecurringRoutine(_, _, _, _, _)).WillRepeatedly(
|
||||
DoAll(SaveArg<2>(&health_check_periodic_routine), Return(1))
|
||||
);
|
||||
|
||||
EXPECT_CALL(mock_rest, mockRestCall(RestAction::ADD, "declare-boolean-variable", _)).WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(mock_rest, mockRestCall(RestAction::SHOW, "health-check-on-demand", _)).WillOnce(
|
||||
WithArg<2>(Invoke(this, &HealthCheckManagerTest::setHealthCheckOnDemand))
|
||||
);
|
||||
|
||||
env.preload();
|
||||
event_listener.registerListener();
|
||||
|
||||
env.init();
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue<bool>("Is Orchestrator", true);
|
||||
|
||||
health_check_manager.init();
|
||||
i_health_check_manager = Singleton::Consume<I_Health_Check_Manager>::from(health_check_manager);
|
||||
}
|
||||
|
||||
~HealthCheckManagerTest()
|
||||
{
|
||||
env.fini();
|
||||
Debug::setNewDefaultStdout(&cout);
|
||||
}
|
||||
|
||||
bool
|
||||
setHealthCheckOnDemand(const unique_ptr<RestInit> &rest_ptr)
|
||||
{
|
||||
health_check_server = rest_ptr->getRest();
|
||||
return true;
|
||||
}
|
||||
|
||||
I_MainLoop::Routine health_check_periodic_routine;
|
||||
StrictMock<MockMainLoop> mock_ml;
|
||||
StrictMock<MockRestApi> mock_rest;
|
||||
StrictMock<MockMessaging> mock_message;
|
||||
stringstream debug_output;
|
||||
ConfigComponent config;
|
||||
Config::I_Config *i_config = nullptr;
|
||||
::Environment env;
|
||||
HealthCheckManager health_check_manager;
|
||||
I_Health_Check_Manager *i_health_check_manager;
|
||||
unique_ptr<ServerRest> health_check_server;
|
||||
TestHealthCheckStatusListener event_listener;
|
||||
};
|
||||
|
||||
TEST_F(HealthCheckManagerTest, runPeriodicHealthCheckTest)
|
||||
{
|
||||
string actual_body;
|
||||
EXPECT_CALL(
|
||||
mock_message,
|
||||
sendMessage(
|
||||
false,
|
||||
_,
|
||||
I_Messaging::Method::PATCH,
|
||||
"/agents",
|
||||
"",
|
||||
_,
|
||||
_,
|
||||
MessageTypeTag::GENERIC
|
||||
)
|
||||
).Times(4).WillRepeatedly(DoAll(SaveArg<1>(&actual_body), Return(string())));
|
||||
|
||||
try {
|
||||
health_check_periodic_routine();
|
||||
} catch (const TestEnd &t) {}
|
||||
|
||||
HealthCheckStatus aggregated_status = i_health_check_manager->getAggregatedStatus();
|
||||
string aggregated_status_str = HealthCheckStatusReply::convertHealthCheckStatusToStr(aggregated_status);
|
||||
|
||||
string expected_healthy_body(
|
||||
"{\n"
|
||||
" \"healthCheck\": {\n"
|
||||
" \"status\": \"Healthy\",\n"
|
||||
" \"errors\": []\n"
|
||||
" }\n"
|
||||
"}"
|
||||
);
|
||||
EXPECT_EQ(actual_body, expected_healthy_body);
|
||||
EXPECT_EQ("Healthy", aggregated_status_str);
|
||||
|
||||
event_listener.setStatus(HealthCheckStatus::DEGRADED);
|
||||
try {
|
||||
health_check_periodic_routine();
|
||||
} catch (const TestEnd &t) {}
|
||||
|
||||
aggregated_status = i_health_check_manager->getAggregatedStatus();
|
||||
aggregated_status_str = HealthCheckStatusReply::convertHealthCheckStatusToStr(aggregated_status);
|
||||
|
||||
string expected_degraded_body(
|
||||
"{\n"
|
||||
" \"healthCheck\": {\n"
|
||||
" \"status\": \"Degraded\",\n"
|
||||
" \"errors\": [\n"
|
||||
" {\n"
|
||||
" \"code\": \"Test city\",\n"
|
||||
" \"message\": [\n"
|
||||
" \"Tel-Aviv\"\n"
|
||||
" ],\n"
|
||||
" \"internal\": true\n"
|
||||
" },\n"
|
||||
" {\n"
|
||||
" \"code\": \"Test team\",\n"
|
||||
" \"message\": [\n"
|
||||
" \"Hapoel\"\n"
|
||||
" ],\n"
|
||||
" \"internal\": true\n"
|
||||
" }\n"
|
||||
" ]\n"
|
||||
" }\n"
|
||||
"}"
|
||||
);
|
||||
EXPECT_EQ(actual_body, expected_degraded_body);
|
||||
EXPECT_EQ("Degraded", aggregated_status_str);
|
||||
}
|
||||
|
||||
TEST_F(HealthCheckManagerTest, runOnDemandHealthCheckTest)
|
||||
{
|
||||
const vector<string> health_check{""};
|
||||
CPTestTempfile health_check_tmp_file(health_check);
|
||||
|
||||
string config_json =
|
||||
"{"
|
||||
" \"agentSettings\": [\n"
|
||||
" {\n"
|
||||
" \"id\": \"yallaHapoel\",\n"
|
||||
" \"key\": \"agent.healthCheck.outputTmpFilePath\",\n"
|
||||
" \"value\": \"" + health_check_tmp_file.fname + "\"\n"
|
||||
" }]\n"
|
||||
"}";
|
||||
|
||||
istringstream ss(config_json);
|
||||
config.preload();
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss);
|
||||
|
||||
stringstream is;
|
||||
is << "{}";
|
||||
health_check_server->performRestCall(is);
|
||||
|
||||
string expected_status =
|
||||
"{\n"
|
||||
" \"allComponentsHealthCheckReplies\": {\n"
|
||||
" \"Test\": {\n"
|
||||
" \"status\": \"Healthy\",\n"
|
||||
" \"extendedStatus\": {\n"
|
||||
" \"city\": \"Tel-Aviv\",\n"
|
||||
" \"team\": \"Hapoel\"\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}";
|
||||
|
||||
string health_check_res = health_check_tmp_file.readFile();
|
||||
EXPECT_EQ(health_check_res, expected_status);
|
||||
}
|
||||
1
components/http_manager/CMakeLists.txt
Normal file
1
components/http_manager/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
add_library(http_manager_comp http_manager.cc http_manager_opaque.cc )
|
||||
379
components/http_manager/http_manager.cc
Executable file
379
components/http_manager/http_manager.cc
Executable file
@@ -0,0 +1,379 @@
|
||||
// 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_manager.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <sys/stat.h>
|
||||
#include <climits>
|
||||
#include <unordered_map>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "table_opaque.h"
|
||||
#include "http_manager_opaque.h"
|
||||
#include "log_generator.h"
|
||||
#include "sasal.h"
|
||||
#include "http_inspection_events.h"
|
||||
|
||||
SASAL_START // HTTP Manager
|
||||
|
||||
USE_DEBUG_FLAG(D_HTTP_MANAGER);
|
||||
|
||||
using namespace std;
|
||||
|
||||
static ostream &
|
||||
operator<<(ostream &os, const EventVerdict &event)
|
||||
{
|
||||
switch (event.getVerdict()) {
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT: return os << "Inspect";
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT: return os << "Accept";
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP: return os << "Drop";
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INJECT: return os << "Inject";
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT: return os << "Irrelevant";
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_RECONF: return os << "Reconf";
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_WAIT: return os << "Wait";
|
||||
}
|
||||
|
||||
dbgAssert(false) << "Illegal Event Verdict value: " << static_cast<uint>(event.getVerdict());
|
||||
return os;
|
||||
}
|
||||
|
||||
class HttpManager::Impl
|
||||
:
|
||||
Singleton::Provide<I_HttpManager>::From<HttpManager>
|
||||
{
|
||||
public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
dbgFlow(D_HTTP_MANAGER);
|
||||
|
||||
i_transaction_table = Singleton::Consume<I_Table>::by<HttpManager>();
|
||||
|
||||
Singleton::Consume<I_Logging>::by<HttpManager>()->addGeneralModifier(compressAppSecLogs);
|
||||
}
|
||||
|
||||
FilterVerdict
|
||||
inspect(const HttpTransactionData &event) override
|
||||
{
|
||||
if (!i_transaction_table->createState<HttpManagerOpaque>()) {
|
||||
dbgWarning(D_HTTP_MANAGER) << "Failed to create new transaction table state - Returning default verdict.";
|
||||
return FilterVerdict(default_verdict);
|
||||
}
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue(app_sec_marker_key, i_transaction_table->keyToString(), EnvKeyAttr::LogSection::MARKER);
|
||||
|
||||
return handleEvent(NewHttpTransactionEvent(event).performNamedQuery());
|
||||
}
|
||||
|
||||
FilterVerdict
|
||||
inspect(const HttpHeader &event, bool is_request) override
|
||||
{
|
||||
if (!i_transaction_table->hasState<HttpManagerOpaque>()) {
|
||||
dbgWarning(D_HTTP_MANAGER) << "Transaction state was not found - Returning default verdict.";
|
||||
return FilterVerdict(default_verdict);
|
||||
}
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue(app_sec_marker_key, i_transaction_table->keyToString(), EnvKeyAttr::LogSection::MARKER);
|
||||
|
||||
auto event_responds =
|
||||
is_request ?
|
||||
HttpRequestHeaderEvent(event).performNamedQuery() :
|
||||
HttpResponseHeaderEvent(event).performNamedQuery();
|
||||
FilterVerdict verdict = handleEvent(event_responds);
|
||||
if (verdict.getVerdict() == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INJECT) {
|
||||
applyInjectionModifications(verdict, event_responds, event.getHeaderIndex());
|
||||
}
|
||||
return verdict;
|
||||
}
|
||||
|
||||
FilterVerdict
|
||||
inspect(const HttpBody &event, bool is_request) override
|
||||
{
|
||||
if (!i_transaction_table->hasState<HttpManagerOpaque>()) {
|
||||
dbgWarning(D_HTTP_MANAGER) << "Transaction state was not found - Returning default verdict.";
|
||||
return FilterVerdict(default_verdict);
|
||||
}
|
||||
|
||||
ngx_http_cp_verdict_e body_size_limit_verdict = handleBodySizeLimit(is_request, event);
|
||||
if (body_size_limit_verdict != ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT) {
|
||||
return FilterVerdict(body_size_limit_verdict);
|
||||
}
|
||||
|
||||
HttpManagerOpaque &state = i_transaction_table->getState<HttpManagerOpaque>();
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue(app_sec_marker_key, i_transaction_table->keyToString(), EnvKeyAttr::LogSection::MARKER);
|
||||
|
||||
FilterVerdict verdict(ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT);
|
||||
if (!is_request && event.getData().size() == 0 && !event.isLastChunk()) {
|
||||
dbgDebug(D_HTTP_MANAGER) << "Skipping inspection of first empty chunk for respond body";
|
||||
return verdict;
|
||||
}
|
||||
|
||||
auto event_responds =
|
||||
is_request ?
|
||||
HttpRequestBodyEvent(event, state.getPreviousDataCache()).performNamedQuery() :
|
||||
HttpResponseBodyEvent(event, state.getPreviousDataCache()).performNamedQuery();
|
||||
verdict = handleEvent(event_responds);
|
||||
state.saveCurrentDataToCache(event.getData());
|
||||
if (verdict.getVerdict() == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INJECT) {
|
||||
applyInjectionModifications(verdict, event_responds, event.getBodyChunkIndex());
|
||||
}
|
||||
return verdict;
|
||||
}
|
||||
|
||||
FilterVerdict
|
||||
inspect(const ResponseCode &event) override
|
||||
{
|
||||
if (!i_transaction_table->hasState<HttpManagerOpaque>()) {
|
||||
dbgWarning(D_HTTP_MANAGER) << "Transaction state was not found - Returning default verdict.";
|
||||
return FilterVerdict(default_verdict);
|
||||
}
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue(app_sec_marker_key, i_transaction_table->keyToString(), EnvKeyAttr::LogSection::MARKER);
|
||||
|
||||
return handleEvent(ResponseCodeEvent(event).performNamedQuery());
|
||||
}
|
||||
|
||||
FilterVerdict
|
||||
inspectEndRequest() override
|
||||
{
|
||||
if (!i_transaction_table->hasState<HttpManagerOpaque>()) {
|
||||
dbgWarning(D_HTTP_MANAGER) << "Transaction state was not found - Returning default verdict.";
|
||||
return FilterVerdict(default_verdict);
|
||||
}
|
||||
|
||||
HttpManagerOpaque &state = i_transaction_table->getState<HttpManagerOpaque>();
|
||||
state.resetPayloadSize();
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue(app_sec_marker_key, i_transaction_table->keyToString(), EnvKeyAttr::LogSection::MARKER);
|
||||
|
||||
return handleEvent(EndRequestEvent().performNamedQuery());
|
||||
}
|
||||
|
||||
FilterVerdict
|
||||
inspectEndTransaction() override
|
||||
{
|
||||
if (!i_transaction_table->hasState<HttpManagerOpaque>()) {
|
||||
dbgWarning(D_HTTP_MANAGER) << "Transaction state was not found - Returning default verdict.";
|
||||
return FilterVerdict(default_verdict);
|
||||
}
|
||||
|
||||
HttpManagerOpaque &state = i_transaction_table->getState<HttpManagerOpaque>();
|
||||
state.resetPayloadSize();
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue(app_sec_marker_key, i_transaction_table->keyToString(), EnvKeyAttr::LogSection::MARKER);
|
||||
|
||||
return handleEvent(EndTransactionEvent().performNamedQuery());
|
||||
}
|
||||
|
||||
FilterVerdict
|
||||
inspectDelayedVerdict() override
|
||||
{
|
||||
if (!i_transaction_table->hasState<HttpManagerOpaque>()) {
|
||||
dbgWarning(D_HTTP_MANAGER) << "Transaction state was not found - Returning default verdict.";
|
||||
return FilterVerdict(default_verdict);
|
||||
}
|
||||
|
||||
ScopedContext ctx;
|
||||
ctx.registerValue(app_sec_marker_key, i_transaction_table->keyToString(), EnvKeyAttr::LogSection::MARKER);
|
||||
|
||||
return handleEvent(WaitTransactionEvent().performNamedQuery());
|
||||
}
|
||||
|
||||
void
|
||||
sendPolicyLog()
|
||||
{
|
||||
LogGen(
|
||||
"Web AppSec Policy Loaded Successfully",
|
||||
ReportIS::Audience::SECURITY,
|
||||
ReportIS::Severity::LOW,
|
||||
ReportIS::Priority::LOW,
|
||||
ReportIS::Tags::THREAT_PREVENTION
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
ngx_http_cp_verdict_e
|
||||
handleBodySizeLimit(bool is_request_body_type, const HttpBody &event)
|
||||
{
|
||||
HttpManagerOpaque &state = i_transaction_table->getState<HttpManagerOpaque>();
|
||||
state.updatePayloadSize(event.getData().size());
|
||||
|
||||
auto size_limit = getConfiguration<uint>(
|
||||
"HTTP manager",
|
||||
is_request_body_type ? "Max Request Body Size" : "Max Response Body Size"
|
||||
);
|
||||
|
||||
string size_limit_verdict = getConfigurationWithDefault<string>(
|
||||
"Accept",
|
||||
"HTTP manager",
|
||||
is_request_body_type ? "Request Size Limit Verdict" : "Response Size Limit Verdict"
|
||||
);
|
||||
|
||||
if (!size_limit.ok() || state.getAggeregatedPayloadSize() < size_limit.unpack()) {
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
|
||||
}
|
||||
|
||||
ngx_http_cp_verdict_e verdict = size_limit_verdict == "Drop" ?
|
||||
ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP :
|
||||
ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
|
||||
dbgDebug(D_HTTP_MANAGER)
|
||||
<< "Transaction body size is over the limit. Max body size: "
|
||||
<< size_limit.unpack()
|
||||
<< ", Returned verdict: "
|
||||
<< size_limit_verdict
|
||||
<< ".";
|
||||
|
||||
state.setManagerVerdict(verdict);
|
||||
return verdict;
|
||||
}
|
||||
|
||||
static void
|
||||
applyInjectionModifications(
|
||||
FilterVerdict &verdict,
|
||||
const vector<pair<string, EventVerdict>> &event_responds,
|
||||
ModifiedChunkIndex event_idx)
|
||||
{
|
||||
for (const pair<string, EventVerdict> &respond : event_responds) {
|
||||
if (respond.second.getVerdict() == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INJECT) {
|
||||
dbgTrace(D_HTTP_MANAGER)
|
||||
<< "Applying inject verdict modifications for security App: "
|
||||
<< respond.first;
|
||||
verdict.addModifications(respond.second.getModifications(), event_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FilterVerdict
|
||||
handleEvent(const vector<pair<string, EventVerdict>> &event_responds)
|
||||
{
|
||||
HttpManagerOpaque &state = i_transaction_table->getState<HttpManagerOpaque>();
|
||||
|
||||
for (const pair<string, EventVerdict> &respond : event_responds) {
|
||||
if (state.getApplicationsVerdict(respond.first) == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT) {
|
||||
dbgTrace(D_HTTP_MANAGER)
|
||||
<< "Skipping event verdict for app that already accepted traffic. App: "
|
||||
<< respond.first;
|
||||
continue;
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_MANAGER)
|
||||
<< "Security app "
|
||||
<< respond.first
|
||||
<< " returned verdict "
|
||||
<< respond.second.getVerdict();
|
||||
|
||||
state.setApplicationVerdict(respond.first, respond.second.getVerdict());
|
||||
}
|
||||
|
||||
return state.getCurrVerdict();
|
||||
}
|
||||
|
||||
static void
|
||||
compressAppSecLogs(LogBulkRest &bulk)
|
||||
{
|
||||
dbgTrace(D_HTTP_MANAGER) << "Starting to reduce logs";
|
||||
|
||||
map<string, uint> app_sec_logs_by_key;
|
||||
|
||||
for (const auto &log : bulk) {
|
||||
auto &markers = log.getMarkers();
|
||||
auto appsec_marker = markers.find(app_sec_marker_key);
|
||||
if (appsec_marker != markers.end()) app_sec_logs_by_key[appsec_marker->second]++;
|
||||
}
|
||||
|
||||
for (const auto &specific_set_of_logs : app_sec_logs_by_key) {
|
||||
if (specific_set_of_logs.second > 1) reduceLogs(bulk, specific_set_of_logs.first);
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_MANAGER) << "Finished logs reduction";
|
||||
}
|
||||
|
||||
static void
|
||||
reduceLogs(LogBulkRest &bulk, const string ¤t_id)
|
||||
{
|
||||
dbgTrace(D_HTTP_MANAGER) << "Reducing logs for marker " << current_id;
|
||||
|
||||
vector<vector<Report>::iterator> relevent_logs;
|
||||
vector<Report>::iterator keep_log = bulk.end();
|
||||
for (auto curr_log = bulk.begin(); curr_log != bulk.end(); ++curr_log) {
|
||||
if (isRelevantLog(curr_log, current_id)) {
|
||||
relevent_logs.push_back(curr_log);
|
||||
if (keep_log == bulk.end() || (isPreventLog(curr_log) && !isPreventLog(keep_log))) keep_log = curr_log;
|
||||
}
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_MANAGER) << "Found " << relevent_logs.size() << " logs that match marker " << current_id;
|
||||
|
||||
// Reverse iteration to avoid iterator invalidation
|
||||
for (auto iter = relevent_logs.rbegin(); iter != relevent_logs.rend(); ++iter) {
|
||||
if (*iter != keep_log) bulk.erase(*iter);
|
||||
}
|
||||
|
||||
dbgTrace(D_HTTP_MANAGER) << "Finished going over maker " << current_id;
|
||||
}
|
||||
|
||||
static bool
|
||||
isRelevantLog(const vector<Report>::iterator &log, const string ¤t_id)
|
||||
{
|
||||
const auto &markers = log->getMarkers();
|
||||
auto app_sec_marker = markers.find(app_sec_marker_key);
|
||||
if (app_sec_marker == markers.end()) return false;
|
||||
return app_sec_marker->second == current_id;
|
||||
}
|
||||
|
||||
static bool
|
||||
isPreventLog(const vector<Report>::iterator &log)
|
||||
{
|
||||
auto res = log->getStringData("securityAction");
|
||||
return res.ok() && *res == "Prevent";
|
||||
}
|
||||
|
||||
I_Table *i_transaction_table;
|
||||
static const ngx_http_cp_verdict_e default_verdict;
|
||||
static const string app_sec_marker_key;
|
||||
};
|
||||
|
||||
const ngx_http_cp_verdict_e HttpManager::Impl::default_verdict(ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP);
|
||||
const string HttpManager::Impl::app_sec_marker_key = "app_sec_marker";
|
||||
|
||||
HttpManager::HttpManager() : Component("HttpManager"), pimpl(make_unique<Impl>()) {}
|
||||
HttpManager::~HttpManager() {}
|
||||
|
||||
void HttpManager::init() { pimpl->init(); }
|
||||
|
||||
void
|
||||
HttpManager::preload()
|
||||
{
|
||||
registerExpectedConfiguration<uint>("HTTP manager", "Previous Buffer Cache size");
|
||||
registerExpectedConfiguration<uint>("HTTP manager", "Max Request Body Size");
|
||||
registerExpectedConfiguration<uint>("HTTP manager", "Max Response Body Size");
|
||||
registerExpectedConfiguration<string>("HTTP manager", "Request Size Limit Verdict");
|
||||
registerExpectedConfiguration<string>("HTTP manager", "Response Size Limit Verdict");
|
||||
registerConfigLoadCb([this] () { pimpl->sendPolicyLog(); });
|
||||
}
|
||||
|
||||
SASAL_END
|
||||
103
components/http_manager/http_manager_opaque.cc
Normal file
103
components/http_manager/http_manager_opaque.cc
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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_manager_opaque.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "sasal.h"
|
||||
|
||||
SASAL_START // HTTP Manager - Transaction data
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_HTTP_MANAGER);
|
||||
|
||||
HttpManagerOpaque::HttpManagerOpaque()
|
||||
:
|
||||
TableOpaqueSerialize<HttpManagerOpaque>(this),
|
||||
prev_data_cache()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
HttpManagerOpaque::setApplicationVerdict(const string &app_name, ngx_http_cp_verdict_e verdict)
|
||||
{
|
||||
applications_verdicts[app_name] = verdict;
|
||||
}
|
||||
|
||||
ngx_http_cp_verdict_e
|
||||
HttpManagerOpaque::getApplicationsVerdict(const string &app_name) const
|
||||
{
|
||||
auto verdict = applications_verdicts.find(app_name);
|
||||
return verdict == applications_verdicts.end() ? ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT : verdict->second;
|
||||
}
|
||||
|
||||
ngx_http_cp_verdict_e
|
||||
HttpManagerOpaque::getCurrVerdict() const
|
||||
{
|
||||
if (manager_verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP) {
|
||||
return manager_verdict;
|
||||
}
|
||||
|
||||
uint accepted_apps = 0;
|
||||
ngx_http_cp_verdict_e verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
|
||||
for (const pair<string, ngx_http_cp_verdict_e> &app_verdic_pair : applications_verdicts) {
|
||||
switch (app_verdic_pair.second) {
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP:
|
||||
return app_verdic_pair.second;
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INJECT:
|
||||
verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INJECT;
|
||||
break;
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT:
|
||||
accepted_apps++;
|
||||
break;
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT:
|
||||
break;
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT:
|
||||
dbgTrace(D_HTTP_MANAGER) << "Verdict 'Irrelevant' is not yet supported. Returning Accept";
|
||||
accepted_apps++;
|
||||
break;
|
||||
case ngx_http_cp_verdict_e::TRAFFIC_VERDICT_WAIT:
|
||||
verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_WAIT;
|
||||
break;
|
||||
default:
|
||||
dbgAssert(false)
|
||||
<< "Received unknown verdict "
|
||||
<< static_cast<int>(app_verdic_pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
return accepted_apps == applications_verdicts.size() ? ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT : verdict;
|
||||
}
|
||||
|
||||
void
|
||||
HttpManagerOpaque::saveCurrentDataToCache(const Buffer &full_data)
|
||||
{
|
||||
uint data_cache_size = getConfigurationWithDefault<uint>(0, "HTTP manager", "Previous Buffer Cache size");
|
||||
if (data_cache_size == 0) {
|
||||
prev_data_cache.clear();
|
||||
return;
|
||||
}
|
||||
prev_data_cache = full_data.getSubBuffer(
|
||||
full_data.size() <= data_cache_size ? 0 : full_data.size() - data_cache_size,
|
||||
full_data.size()
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
HttpManagerOpaque::updatePayloadSize(const uint curr_payload_size)
|
||||
{
|
||||
aggregated_payload_size += curr_payload_size;
|
||||
}
|
||||
|
||||
SASAL_END
|
||||
55
components/http_manager/http_manager_opaque.h
Normal file
55
components/http_manager/http_manager_opaque.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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_MANAGER_OPAQUE_H__
|
||||
#define __HTTP_MANAGER_OPAQUE_H__
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "buffer.h"
|
||||
#include "table_opaque.h"
|
||||
#include "nginx_attachment_common.h"
|
||||
|
||||
class HttpManagerOpaque : public TableOpaqueSerialize<HttpManagerOpaque>
|
||||
{
|
||||
public:
|
||||
HttpManagerOpaque();
|
||||
|
||||
void setApplicationVerdict(const std::string &app_name, ngx_http_cp_verdict_e verdict);
|
||||
ngx_http_cp_verdict_e getApplicationsVerdict(const std::string &app_name) const;
|
||||
void setManagerVerdict(ngx_http_cp_verdict_e verdict) { manager_verdict = verdict; }
|
||||
ngx_http_cp_verdict_e getManagerVerdict() const { return manager_verdict; }
|
||||
ngx_http_cp_verdict_e getCurrVerdict() const;
|
||||
void saveCurrentDataToCache(const Buffer &full_data);
|
||||
const Buffer & getPreviousDataCache() const { return prev_data_cache; }
|
||||
uint getAggeregatedPayloadSize() const { return aggregated_payload_size; }
|
||||
void updatePayloadSize(const uint curr_payload);
|
||||
void resetPayloadSize() { aggregated_payload_size = 0; }
|
||||
|
||||
// LCOV_EXCL_START - sync functions, can only be tested once the sync module exists
|
||||
template <typename T> void serialize(T &ar, uint) { ar(applications_verdicts, prev_data_cache); }
|
||||
static std::unique_ptr<TableOpaqueBase> prototype() { return std::make_unique<HttpManagerOpaque>(); }
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
static const std::string name() { return "HttpTransactionData"; }
|
||||
static uint currVer() { return 0; }
|
||||
static uint minVer() { return 0; }
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, ngx_http_cp_verdict_e> applications_verdicts;
|
||||
ngx_http_cp_verdict_e manager_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
|
||||
Buffer prev_data_cache;
|
||||
uint aggregated_payload_size = 0;
|
||||
};
|
||||
|
||||
#endif // __HTTP_MANAGER_OPAQUE_H__
|
||||
5
components/http_transaction_data/CMakeLists.txt
Executable file
5
components/http_transaction_data/CMakeLists.txt
Executable file
@@ -0,0 +1,5 @@
|
||||
add_definitions(-DUSERSPACE)
|
||||
|
||||
add_library(http_transaction_data http_transaction_data.cc)
|
||||
|
||||
add_subdirectory(http_transaction_data_ut)
|
||||
265
components/http_transaction_data/http_transaction_data.cc
Normal file
265
components/http_transaction_data/http_transaction_data.cc
Normal file
@@ -0,0 +1,265 @@
|
||||
// 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_transaction_data.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sstream>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "enum_array.h"
|
||||
#include "sasal.h"
|
||||
#include "buffer.h"
|
||||
#include "nginx_attachment_common.h"
|
||||
|
||||
SASAL_START // HTTP Manager - Transaction data
|
||||
|
||||
using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_NGINX_ATTACHMENT);
|
||||
|
||||
enum class ETransactionData {
|
||||
HTTP_PROTO,
|
||||
METHOD,
|
||||
HOST_NAME,
|
||||
LISTENING_IP,
|
||||
LISTENING_PORT,
|
||||
URI,
|
||||
CLIENT_IP,
|
||||
CLIENT_PORT,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
const string HttpTransactionData::http_proto_ctx = "transaction_http_proto";
|
||||
const string HttpTransactionData::method_ctx = "transaction_method";
|
||||
const string HttpTransactionData::host_name_ctx = "transaction_host_name";
|
||||
const string HttpTransactionData::listening_ip_ctx = "transaction_listening_ip";
|
||||
const string HttpTransactionData::listening_port_ctx = "transaction_listening_port";
|
||||
const string HttpTransactionData::uri_ctx = "transaction_uri";
|
||||
const string HttpTransactionData::uri_path_decoded = "transaction_uri_path_decoded";
|
||||
const string HttpTransactionData::uri_query_decoded = "transaction_uri_query_decoded";
|
||||
const string HttpTransactionData::client_ip_ctx = "transaction_client_ip";
|
||||
const string HttpTransactionData::client_port_ctx = "transaction_client_port";
|
||||
const string HttpTransactionData::req_headers = "transaction_request_headers";
|
||||
const string HttpTransactionData::req_body = "transaction_request_body";
|
||||
const string HttpTransactionData::source_identifier = "sourceIdentifiers";
|
||||
const string HttpTransactionData::proxy_ip_ctx = "proxy_ip";
|
||||
|
||||
const CompressionType HttpTransactionData::default_response_content_encoding = CompressionType::NO_COMPRESSION;
|
||||
|
||||
Maybe<uint16_t>
|
||||
deserializeUintParam(const Buffer &data, uint &cur_pos)
|
||||
{
|
||||
// Int value is encoded in binary form
|
||||
auto value = data.getTypePtr<uint16_t>(cur_pos);
|
||||
|
||||
if (!value.ok()) {
|
||||
return genError("Failed to get Uint param " + value.getErr());
|
||||
}
|
||||
|
||||
cur_pos += sizeof(uint16_t);
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully parsed the number parameter. Value: " << *(value.unpack());
|
||||
|
||||
return *(value.unpack());
|
||||
}
|
||||
|
||||
Maybe<string>
|
||||
deserializeStrParam(const Buffer &data, uint &cur_pos)
|
||||
{
|
||||
//String is encoded by 16-bit uint representing length followed by const c-type string data bytes
|
||||
Maybe<uint16_t> str_size = deserializeUintParam(data, cur_pos);
|
||||
if (!str_size.ok()) return genError("Could Not parse string size value: " + str_size.getErr());
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "Deserializing string parameter. Current position: "
|
||||
<< cur_pos
|
||||
<< ", String size: "
|
||||
<< *str_size;
|
||||
|
||||
string res = "";
|
||||
if (*str_size > 0) {
|
||||
auto value = data.getPtr(cur_pos, *str_size);
|
||||
if (!value.ok()) {
|
||||
return genError("Failed to get String param " + value.getErr());
|
||||
}
|
||||
|
||||
const u_char *ptr = value.unpack();
|
||||
res = string(reinterpret_cast<const char *>(ptr), *str_size);
|
||||
}
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "Successfully parsed string parameter. Result: "
|
||||
<< res
|
||||
<< ", Length: "
|
||||
<< to_string(*str_size);
|
||||
|
||||
cur_pos += *str_size;
|
||||
|
||||
return move(res);
|
||||
}
|
||||
|
||||
Maybe<IPAddr>
|
||||
deserializeIpAddrParam(const Buffer &data, uint &cur_pos)
|
||||
{
|
||||
Maybe<string> str_value = deserializeStrParam(data, cur_pos);
|
||||
if (!str_value.ok()) return str_value.passErr();
|
||||
|
||||
Maybe<IPAddr> ip = IPAddr::createIPAddr(str_value.unpackMove());
|
||||
if (!ip.ok()) return genError("Could not parse IP Address: " + ip.getErr());
|
||||
|
||||
return move(ip.unpackMove());
|
||||
}
|
||||
|
||||
Maybe<HttpTransactionData>
|
||||
HttpTransactionData::createTransactionData(const Buffer &transaction_raw_data)
|
||||
{
|
||||
// Deserialize TransactionData from binary blob sent from attachment
|
||||
uint cur_pos = 0;
|
||||
|
||||
dbgTrace(D_NGINX_ATTACHMENT)
|
||||
<< "Parsing buffer "
|
||||
<< dumpHex(transaction_raw_data)
|
||||
<< " of size "
|
||||
<< transaction_raw_data.size();
|
||||
|
||||
Maybe<string> http_protocol = deserializeStrParam(transaction_raw_data, cur_pos);
|
||||
if (!http_protocol.ok()) {
|
||||
return genError("Could not deserialize HTTP protocol: " + http_protocol.getErr());
|
||||
} else {
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized HTTP protocol: " << http_protocol.unpack();
|
||||
}
|
||||
|
||||
Maybe<string> http_method = deserializeStrParam(transaction_raw_data, cur_pos);
|
||||
if (!http_method.ok()) {
|
||||
return genError("Could not deserialize HTTP method: " + http_method.getErr());
|
||||
} else {
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized HTTP method: " << http_method.unpack();
|
||||
}
|
||||
|
||||
Maybe<string> host_name = deserializeStrParam(transaction_raw_data, cur_pos);
|
||||
if (!host_name.ok()) {
|
||||
return genError("Could not deserialize host name: " + host_name.getErr());
|
||||
} else {
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized host name: " << host_name.unpack();
|
||||
}
|
||||
|
||||
Maybe<IPAddr> listening_addr = deserializeIpAddrParam(transaction_raw_data, cur_pos);
|
||||
if (!listening_addr.ok()) {
|
||||
return genError("Could not deserialize listening address: " + listening_addr.getErr());
|
||||
} else {
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized listening address: " << listening_addr.unpack();
|
||||
}
|
||||
|
||||
Maybe<uint32_t> listening_port = deserializeUintParam(transaction_raw_data, cur_pos);
|
||||
if (!listening_port.ok()) {
|
||||
return genError("Could not deserialize listening port: " + listening_port.getErr());
|
||||
} else {
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized listening port: " << listening_port.unpack();
|
||||
}
|
||||
|
||||
Maybe<string> uri = deserializeStrParam(transaction_raw_data, cur_pos);
|
||||
if (!uri.ok()) {
|
||||
return genError("Could not deserialize URI: " + uri.getErr());
|
||||
} else {
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized URI: " << uri.unpack();
|
||||
}
|
||||
|
||||
Maybe<IPAddr> client_addr = deserializeIpAddrParam(transaction_raw_data, cur_pos);
|
||||
if (!client_addr.ok()) {
|
||||
return genError("Could not deserialize client address: " + client_addr.getErr());
|
||||
} else {
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized client address: " << client_addr.unpack();
|
||||
}
|
||||
|
||||
Maybe<uint32_t> client_port = deserializeUintParam(transaction_raw_data, cur_pos);
|
||||
if (!client_port.ok()) {
|
||||
return genError("Could not deserialize client port: " + client_port.getErr());
|
||||
} else {
|
||||
dbgTrace(D_NGINX_ATTACHMENT) << "Successfully deserialized client port: " << client_port.unpack();
|
||||
}
|
||||
|
||||
// Fail if after parsing exact number of items, we didn't exactly consume whole buffer
|
||||
if (cur_pos != transaction_raw_data.size()) {
|
||||
dbgWarning(D_NGINX_ATTACHMENT) << "Nothing to deserialize, but raw data still remain";
|
||||
return genError("Finished deserialization and raw data still exist - Probably corrupted buffer.");
|
||||
}
|
||||
|
||||
HttpTransactionData transaction(
|
||||
http_protocol.unpackMove(),
|
||||
http_method.unpackMove(),
|
||||
host_name.unpackMove(),
|
||||
listening_addr.unpackMove(),
|
||||
listening_port.unpackMove(),
|
||||
uri.unpackMove(),
|
||||
client_addr.unpackMove(),
|
||||
client_port.unpackMove()
|
||||
);
|
||||
|
||||
return move(transaction);
|
||||
}
|
||||
|
||||
HttpTransactionData::HttpTransactionData (
|
||||
string _http_proto,
|
||||
string _method,
|
||||
string _host_name,
|
||||
IPAddr _listening_ip,
|
||||
uint16_t _listening_port,
|
||||
string _uri,
|
||||
IPAddr _client_ip,
|
||||
uint16_t _client_port
|
||||
)
|
||||
:
|
||||
http_proto(move(_http_proto)),
|
||||
method(move(_method)),
|
||||
host_name(move(_host_name)),
|
||||
listening_ip(move(_listening_ip)),
|
||||
listening_port(move(_listening_port)),
|
||||
uri(move(_uri)),
|
||||
client_ip(move(_client_ip)),
|
||||
client_port(move(_client_port)),
|
||||
is_request(true),
|
||||
response_content_encoding(default_response_content_encoding)
|
||||
{
|
||||
}
|
||||
|
||||
HttpTransactionData::HttpTransactionData()
|
||||
:
|
||||
HttpTransactionData::HttpTransactionData(
|
||||
"",
|
||||
"GET",
|
||||
"",
|
||||
IPAddr(),
|
||||
-1,
|
||||
"",
|
||||
IPAddr(),
|
||||
-1
|
||||
)
|
||||
{}
|
||||
|
||||
void
|
||||
HttpTransactionData::print(ostream &out_stream) const
|
||||
{
|
||||
out_stream << http_proto << " " << method << endl;
|
||||
out_stream << "From: " << client_ip << ":" << client_port << endl;
|
||||
out_stream << "To: "
|
||||
<< host_name
|
||||
<< uri
|
||||
<< " (listening on "
|
||||
<< listening_ip
|
||||
<< ":"
|
||||
<< listening_port
|
||||
<< ")"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
SASAL_END
|
||||
7
components/http_transaction_data/http_transaction_data_ut/CMakeLists.txt
Executable file
7
components/http_transaction_data/http_transaction_data_ut/CMakeLists.txt
Executable file
@@ -0,0 +1,7 @@
|
||||
include_directories(${CMAKE_SOURCE_DIR}/components/include)
|
||||
|
||||
add_unit_test(
|
||||
http_transaction_data_ut
|
||||
"http_transaction_data_ut.cc"
|
||||
"http_transaction_data;http_transaction_data;connkey;${RT_LIBRARY}"
|
||||
)
|
||||
@@ -0,0 +1,127 @@
|
||||
#include "http_transaction_data.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "cptest.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
Buffer
|
||||
encodeInt16(uint16_t val)
|
||||
{
|
||||
vector<u_char> raw_data(reinterpret_cast<u_char*>(&val), reinterpret_cast<u_char*>(&val) + sizeof(uint16_t));
|
||||
return move(Buffer(raw_data));
|
||||
}
|
||||
|
||||
class HttpTransactionTest : public Test
|
||||
{
|
||||
public:
|
||||
Buffer
|
||||
createValidBuf()
|
||||
{
|
||||
Buffer protocol_length = Buffer(encodeInt16(strlen("HTTP/1.1")));
|
||||
|
||||
return
|
||||
protocol_length +
|
||||
Buffer("HTTP/1.1") +
|
||||
encodeInt16(3) +
|
||||
Buffer("GET") +
|
||||
encodeInt16(9) +
|
||||
Buffer("localhost") +
|
||||
encodeInt16(7) +
|
||||
Buffer("0.0.0.0") +
|
||||
encodeInt16(443) +
|
||||
encodeInt16(10) +
|
||||
Buffer("/user-app/") +
|
||||
encodeInt16(9) +
|
||||
Buffer("127.0.0.1") +
|
||||
encodeInt16(47423);
|
||||
}
|
||||
|
||||
Buffer
|
||||
createBadVerBuf()
|
||||
{
|
||||
Buffer protocol_length = Buffer(encodeInt16(strlen("HTTP/1.1")));
|
||||
|
||||
return
|
||||
protocol_length +
|
||||
Buffer("HTTP/1");
|
||||
}
|
||||
|
||||
Buffer
|
||||
createBadAddressBuf()
|
||||
{
|
||||
Buffer protocol_length = Buffer(encodeInt16(strlen("HTTP/1.1")));
|
||||
|
||||
return
|
||||
protocol_length +
|
||||
Buffer("HTTP/1.1") +
|
||||
encodeInt16(3) +
|
||||
Buffer("GET") +
|
||||
encodeInt16(9) +
|
||||
Buffer("localhost") +
|
||||
encodeInt16(14) +
|
||||
Buffer("this.is.not.IP") +
|
||||
encodeInt16(443) +
|
||||
encodeInt16(10) +
|
||||
Buffer("/user-app/") +
|
||||
encodeInt16(9) +
|
||||
Buffer("127.0.0.1") +
|
||||
encodeInt16(47423);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(HttpTransactionTest, TestEmptyTransactionData)
|
||||
{
|
||||
HttpTransactionData data;
|
||||
stringstream data_stream;
|
||||
data.print(data_stream);
|
||||
string data_string(
|
||||
" GET\nFrom: Uninitialized IP address:65535\nTo: (listening on Uninitialized IP address:65535)\n"
|
||||
);
|
||||
EXPECT_EQ(data_stream.str(), data_string);
|
||||
}
|
||||
|
||||
TEST_F(HttpTransactionTest, TestTransactionDataFromBuf)
|
||||
{
|
||||
HttpTransactionData data = HttpTransactionData::createTransactionData(createValidBuf()).unpack();
|
||||
stringstream data_stream;
|
||||
data.print(data_stream);
|
||||
string data_string(
|
||||
"HTTP/1.1 GET\nFrom: 127.0.0.1:47423\nTo: localhost/user-app/ (listening on 0.0.0.0:443)\n"
|
||||
);
|
||||
EXPECT_EQ(data_stream.str(), data_string);
|
||||
|
||||
EXPECT_EQ(data.getSourceIP(), IPAddr::createIPAddr("127.0.0.1").unpack());
|
||||
EXPECT_EQ(data.getSourcePort(), 47423);
|
||||
EXPECT_EQ(data.getListeningIP(), IPAddr::createIPAddr("0.0.0.0").unpack());
|
||||
EXPECT_EQ(data.getListeningPort(), 443);
|
||||
EXPECT_EQ(data.getDestinationHost(), "localhost");
|
||||
EXPECT_EQ(data.getHttpProtocol(), "HTTP/1.1");
|
||||
EXPECT_EQ(data.getURI(), "/user-app/");
|
||||
EXPECT_EQ(data.getHttpMethod(), "GET");
|
||||
}
|
||||
|
||||
TEST_F(HttpTransactionTest, TestTransactionDataBadVer)
|
||||
{
|
||||
auto data = HttpTransactionData::createTransactionData(createBadVerBuf());
|
||||
ASSERT_FALSE(data.ok());
|
||||
EXPECT_EQ(
|
||||
data.getErr(),
|
||||
"Could not deserialize HTTP protocol: "
|
||||
"Failed to get String param Cannot get internal pointer beyond the buffer limits"
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(HttpTransactionTest, TestTransactionDataBadAddress)
|
||||
{
|
||||
auto data = HttpTransactionData::createTransactionData(createBadAddressBuf());
|
||||
ASSERT_FALSE(data.ok());
|
||||
EXPECT_EQ(
|
||||
data.getErr(),
|
||||
"Could not deserialize listening address: "
|
||||
"Could not parse IP Address: String 'this.is.not.IP' is not a valid IPv4/IPv6 address"
|
||||
);
|
||||
}
|
||||
71
components/include/WaapEnums.h
Executable file
71
components/include/WaapEnums.h
Executable file
@@ -0,0 +1,71 @@
|
||||
// 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 __WAAP_ENUMS_H__
|
||||
#define __WAAP_ENUMS_H__
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
#define NO_THREAT_FINAL_SCORE 0.0
|
||||
#define INFO_THREAT_THRESHOLD 1.0
|
||||
#define LOW_THREAT_THRESHOLD 3.0
|
||||
#define MED_THREAT_THRESHOLD 6.0
|
||||
#define MAX_FINAL_SCORE 10.0
|
||||
#define ATTACK_IN_PARAM "attack_in_param"
|
||||
|
||||
enum ThreatLevel {
|
||||
NO_THREAT = 0,
|
||||
THREAT_INFO,
|
||||
LOW_THREAT,
|
||||
MEDIUM_THREAT,
|
||||
HIGH_THREAT
|
||||
};
|
||||
|
||||
enum BlockType {
|
||||
NOT_BLOCKING,
|
||||
FORCE_EXCEPTION,
|
||||
FORCE_BLOCK,
|
||||
API_BLOCK,
|
||||
BOT_BLOCK,
|
||||
WAF_BLOCK,
|
||||
CSRF_BLOCK,
|
||||
LIMIT_BLOCK
|
||||
};
|
||||
|
||||
enum ParamType {
|
||||
UNKNOWN_PARAM_TYPE,
|
||||
HTML_PARAM_TYPE,
|
||||
URL_PARAM_TYPE,
|
||||
FREE_TEXT_PARAM_TYPE,
|
||||
PIPE_PARAM_TYPE,
|
||||
LONG_RANDOM_TEXT_PARAM_TYPE,
|
||||
BASE64_PARAM_TYPE,
|
||||
ADMINISTRATOR_CONFIG_PARAM_TYPE,
|
||||
FILE_PATH_PARAM_TYPE,
|
||||
SEMICOLON_DELIMITED_PARAM_TYPE,
|
||||
ASTERISK_DELIMITED_PARAM_TYPE,
|
||||
COMMA_DELIMITED_PARAM_TYPE,
|
||||
AMPERSAND_DELIMITED_PARAM_TYPE,
|
||||
BINARY_PARAM_TYPE,
|
||||
PARAM_TYPE_COUNT
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<ParamType>
|
||||
{
|
||||
std::size_t operator()(const ParamType& type) const noexcept { return (size_t)type; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
47
components/include/attachment_registrator.h
Executable file
47
components/include/attachment_registrator.h
Executable file
@@ -0,0 +1,47 @@
|
||||
// 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 __ATTACHMENT_REGISTRATOR_H__
|
||||
#define __ATTACHMENT_REGISTRATOR_H__
|
||||
|
||||
#include "singleton.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "i_shell_cmd.h"
|
||||
#include "i_socket_is.h"
|
||||
#include "attachment_types.h"
|
||||
#include "component.h"
|
||||
|
||||
#define default_keep_alive_path "/etc/cp/attachmentRegistrator/expiration-socket"
|
||||
|
||||
class AttachmentRegistrator
|
||||
:
|
||||
public Component,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_ShellCmd>,
|
||||
Singleton::Consume<I_Socket>
|
||||
{
|
||||
public:
|
||||
AttachmentRegistrator();
|
||||
~AttachmentRegistrator();
|
||||
|
||||
void preload();
|
||||
|
||||
void init();
|
||||
void fini();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __ATTACHMENT_REGISTRATOR_H__
|
||||
48
components/include/byteorder.h
Executable file
48
components/include/byteorder.h
Executable file
@@ -0,0 +1,48 @@
|
||||
#ifndef __BYTEORDER_H__
|
||||
#define __BYTEORDER_H__
|
||||
|
||||
// Byte Order (Net-to-Host, Host-to-Net) operations
|
||||
//
|
||||
// C provides htons, ntohs, htonl, ntohl, but they're not "constexpr" so are unusable in case labels.
|
||||
// C++ proposal N3620 adds some function, but it's not accepted (yet?). It uses templates which are,
|
||||
// IMO, a bit complicated so I chose not to adapt it.
|
||||
|
||||
static inline constexpr uint16_t
|
||||
constHTONS(uint16_t h_ord)
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
return ((h_ord>>8) & 0xff) |
|
||||
((h_ord&0xff) << 8);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
return h_ord;
|
||||
#else
|
||||
#error unknown byte order
|
||||
#endif // __BYTE_ORDER
|
||||
}
|
||||
|
||||
static inline constexpr uint16_t
|
||||
constNTOHS(uint16_t n_ord)
|
||||
{
|
||||
return constHTONS(n_ord); // Same thing
|
||||
}
|
||||
|
||||
static inline constexpr uint32_t
|
||||
constHTONL(uint32_t h_ord)
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
return ((constHTONS(h_ord>>16)) & 0xffff) |
|
||||
((constHTONS(h_ord&0xffff)) << 16);
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
return h_ord;
|
||||
#else
|
||||
#error unknown byte order
|
||||
#endif // __BYTE_ORDER
|
||||
}
|
||||
|
||||
static inline constexpr uint32_t
|
||||
constNTOHL(uint32_t n_ord)
|
||||
{
|
||||
return constHTONL(n_ord); // Same thing
|
||||
}
|
||||
|
||||
#endif // __BYTEORDER_H__
|
||||
43
components/include/details_resolver.h
Normal file
43
components/include/details_resolver.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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 __DETAILS_RESOLVER_H__
|
||||
#define __DETAILS_RESOLVER_H__
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "i_orchestration_tools.h"
|
||||
#include "i_details_resolver.h"
|
||||
#include "i_shell_cmd.h"
|
||||
#include "singleton.h"
|
||||
#include "component.h"
|
||||
|
||||
class DetailsResolver
|
||||
:
|
||||
public Component,
|
||||
Singleton::Provide<I_DetailsResolver>,
|
||||
Singleton::Consume<I_OrchestrationTools>
|
||||
{
|
||||
public:
|
||||
DetailsResolver();
|
||||
~DetailsResolver();
|
||||
|
||||
void preload() override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __DETAILS_RESOLVER_H__
|
||||
50
components/include/downloader.h
Executable file
50
components/include/downloader.h
Executable file
@@ -0,0 +1,50 @@
|
||||
// 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 __DOWNLOADER_H__
|
||||
#define __DOWNLOADER_H__
|
||||
|
||||
#include "i_downloader.h"
|
||||
#include "i_orchestration_tools.h"
|
||||
#include "i_update_communication.h"
|
||||
#include "i_encryptor.h"
|
||||
#include "url_parser.h"
|
||||
#include "i_agent_details.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "singleton.h"
|
||||
#include "component.h"
|
||||
|
||||
class Downloader
|
||||
:
|
||||
public Component,
|
||||
Singleton::Provide<I_Downloader>,
|
||||
Singleton::Consume<I_AgentDetails>,
|
||||
Singleton::Consume<I_Encryptor>,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_OrchestrationTools>,
|
||||
Singleton::Consume<I_UpdateCommunication>
|
||||
{
|
||||
public:
|
||||
Downloader();
|
||||
~Downloader();
|
||||
|
||||
void preload() override;
|
||||
|
||||
void init() override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __DOWNLOADER_H__
|
||||
43
components/include/external_sdk_server.h
Executable file
43
components/include/external_sdk_server.h
Executable file
@@ -0,0 +1,43 @@
|
||||
// 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 __EXTERNAL_SDK_SERVER_H__
|
||||
#define __EXTERNAL_SDK_SERVER_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "i_external_sdk_server.h"
|
||||
#include "i_rest_api.h"
|
||||
#include "component.h"
|
||||
|
||||
class ExternalSdkServer
|
||||
:
|
||||
public Component,
|
||||
Singleton::Provide<I_ExternalSdkServer>,
|
||||
Singleton::Consume<I_RestApi>
|
||||
{
|
||||
public:
|
||||
ExternalSdkServer();
|
||||
~ExternalSdkServer();
|
||||
|
||||
void init();
|
||||
void fini();
|
||||
|
||||
void preload();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __EXTERNAL_SDK_SERVER_H__
|
||||
31
components/include/generic_rulebase/asset.h
Executable file
31
components/include/generic_rulebase/asset.h
Executable file
@@ -0,0 +1,31 @@
|
||||
// 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 __ASSET_H__
|
||||
#define __ASSET_H__
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "i_environment.h"
|
||||
|
||||
class Asset
|
||||
{
|
||||
public:
|
||||
const std::map<Context::MetaDataType, std::string> & getAttrs() const { return attr; }
|
||||
void setAttr(Context::MetaDataType type, const std::string &attr_val) { attr[type] = attr_val; }
|
||||
|
||||
private:
|
||||
std::map<Context::MetaDataType, std::string> attr;
|
||||
};
|
||||
|
||||
#endif // __ASSET_H__
|
||||
91
components/include/generic_rulebase/assets_config.h
Executable file
91
components/include/generic_rulebase/assets_config.h
Executable file
@@ -0,0 +1,91 @@
|
||||
// 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 __ASSETS_CONFIG_H__
|
||||
#define __ASSETS_CONFIG_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "generic_rulebase_context.h"
|
||||
#include "c_common/ip_common.h"
|
||||
#include "connkey.h"
|
||||
|
||||
class RuleAsset
|
||||
{
|
||||
public:
|
||||
class AssetUrl
|
||||
{
|
||||
public:
|
||||
void
|
||||
load(cereal::JSONInputArchive &archive_in);
|
||||
const std::string & getProtocol() const { return protocol; }
|
||||
const std::string & getIp() const { return ip; }
|
||||
const std::string & getPort() const { return port; }
|
||||
|
||||
uint8_t getParsedProtocol() const { return parsed_proto; }
|
||||
const IpAddress & getParsedIp() const { return parsed_ip; }
|
||||
uint16_t getParsedPort() const { return parsed_port; }
|
||||
bool isAnyIp() const { return is_any_ip; }
|
||||
bool isAnyPort() const { return is_any_port; }
|
||||
bool isAnyProto() const { return is_any_proto; }
|
||||
|
||||
private:
|
||||
static IpAddress ConvertToIpAddress(const IPAddr &addr);
|
||||
|
||||
std::string protocol;
|
||||
std::string ip;
|
||||
std::string port;
|
||||
IpAddress parsed_ip;
|
||||
uint16_t parsed_port;
|
||||
uint8_t parsed_proto;
|
||||
bool is_any_ip;
|
||||
bool is_any_port;
|
||||
bool is_any_proto;
|
||||
};
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const GenericConfigId & getId() const { return asset_id; }
|
||||
const std::string & getName() const { return asset_name; }
|
||||
const std::vector<AssetUrl> & getUrls() const { return asset_urls; }
|
||||
|
||||
private:
|
||||
GenericConfigId asset_id;
|
||||
std::string asset_name;
|
||||
std::vector<AssetUrl> asset_urls;
|
||||
};
|
||||
|
||||
class Assets
|
||||
{
|
||||
public:
|
||||
static void preload();
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
try {
|
||||
cereal::load(archive_in, assets);
|
||||
}catch (const cereal::Exception &) {
|
||||
}
|
||||
}
|
||||
|
||||
static const Assets empty_assets_config;
|
||||
|
||||
const std::vector<RuleAsset> & getAssets() const { return assets; }
|
||||
|
||||
private:
|
||||
std::vector<RuleAsset> assets;
|
||||
};
|
||||
|
||||
#endif //__ASSETS_CONFIG_H__
|
||||
36
components/include/generic_rulebase/evaluators/asset_eval.h
Executable file
36
components/include/generic_rulebase/evaluators/asset_eval.h
Executable 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 __ASSET_EVAL_H__
|
||||
#define __ASSET_EVAL_H__
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
|
||||
class AssetMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
AssetMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "assetId"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::string asset_id;
|
||||
};
|
||||
|
||||
#endif // __ASSET_EVAL_H__
|
||||
127
components/include/generic_rulebase/evaluators/connection_eval.h
Executable file
127
components/include/generic_rulebase/evaluators/connection_eval.h
Executable file
@@ -0,0 +1,127 @@
|
||||
// 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 __CONNECTION_EVAL_H__
|
||||
#define __CONNECTION_EVAL_H__
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
#include "connkey.h"
|
||||
|
||||
class IpAddressMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
IpAddressMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "ipAddress"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::vector<CustomRange<IPAddr>> values;
|
||||
};
|
||||
|
||||
class SourceIpMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
SourceIpMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "sourceIP"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::vector<CustomRange<IPAddr>> values;
|
||||
};
|
||||
|
||||
class DestinationIpMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
DestinationIpMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "destinationIP"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::vector<CustomRange<IPAddr>> values;
|
||||
};
|
||||
|
||||
class SourcePortMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
SourcePortMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "sourcePort"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::vector<CustomRange<PortNumber>> values;
|
||||
};
|
||||
|
||||
class ListeningPortMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
ListeningPortMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "listeningPort"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::vector<CustomRange<PortNumber>> values;
|
||||
};
|
||||
|
||||
class IpProtocolMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
IpProtocolMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "ipProtocol"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::vector<CustomRange<IPProto>> values;
|
||||
};
|
||||
|
||||
class UrlMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
UrlMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "url"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::vector<std::string> values;
|
||||
};
|
||||
|
||||
#endif // __CONNECTION_EVAL_H__
|
||||
74
components/include/generic_rulebase/evaluators/http_transaction_data_eval.h
Executable file
74
components/include/generic_rulebase/evaluators/http_transaction_data_eval.h
Executable file
@@ -0,0 +1,74 @@
|
||||
// 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_TRANSACTION_DATA_EVAL_H__
|
||||
#define __HTTP_TRANSACTION_DATA_EVAL_H__
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
#include "connkey.h"
|
||||
|
||||
class EqualHost : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
EqualHost(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "EqualHost"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
private:
|
||||
std::string host;
|
||||
};
|
||||
|
||||
class EqualListeningIP : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
EqualListeningIP(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "EqualListeningIP"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
private:
|
||||
IPAddr listening_ip;
|
||||
};
|
||||
|
||||
class EqualListeningPort : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
EqualListeningPort(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "EqualListeningPort"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
private:
|
||||
PortNumber listening_port;
|
||||
};
|
||||
|
||||
class BeginWithUri : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
BeginWithUri(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "BeginWithUri"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
private:
|
||||
std::string uri_prefix;
|
||||
};
|
||||
|
||||
#endif // __HTTP_TRANSACTION_DATA_EVAL_H__
|
||||
36
components/include/generic_rulebase/evaluators/parameter_eval.h
Executable file
36
components/include/generic_rulebase/evaluators/parameter_eval.h
Executable 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 __PARAMETER_EVAL_H__
|
||||
#define __PARAMETER_EVAL_H__
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
|
||||
class ParameterMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
ParameterMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "parameterId"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::string parameter_id;
|
||||
};
|
||||
|
||||
#endif // __PARAMETER_EVAL_H__
|
||||
36
components/include/generic_rulebase/evaluators/practice_eval.h
Executable file
36
components/include/generic_rulebase/evaluators/practice_eval.h
Executable 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 __PRACTICE_EVAL_H__
|
||||
#define __PRACTICE_EVAL_H__
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
|
||||
class PracticeMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
PracticeMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "practiceId"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::string practice_id;
|
||||
};
|
||||
|
||||
#endif // __PRACTICE_EVAL_H__
|
||||
43
components/include/generic_rulebase/evaluators/query_eval.h
Executable file
43
components/include/generic_rulebase/evaluators/query_eval.h
Executable file
@@ -0,0 +1,43 @@
|
||||
// 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 __QUERY_EVAL_H__
|
||||
#define __QUERY_EVAL_H__
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "i_generic_rulebase.h"
|
||||
#include "singleton.h"
|
||||
|
||||
class QueryMatcher
|
||||
:
|
||||
public EnvironmentEvaluator<bool>,
|
||||
Singleton::Consume<I_Environment>,
|
||||
Singleton::Consume<I_GenericRulebase>
|
||||
{
|
||||
public:
|
||||
QueryMatcher(const std::vector<std::string> &query_params);
|
||||
|
||||
static std::string getName() { return "matchQuery"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
private:
|
||||
static const std::string contextKeyToString(Context::MetaDataType type);
|
||||
|
||||
std::string key;
|
||||
std::unordered_set<std::string> values;
|
||||
bool is_any = false;
|
||||
};
|
||||
|
||||
#endif // __QUERY_EVAL_H__
|
||||
36
components/include/generic_rulebase/evaluators/trigger_eval.h
Executable file
36
components/include/generic_rulebase/evaluators/trigger_eval.h
Executable 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 __TRIGGER_EVAL_H__
|
||||
#define __TRIGGER_EVAL_H__
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
|
||||
class TriggerMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
TriggerMatcher(const std::vector<std::string> ¶ms);
|
||||
|
||||
static std::string getName() { return "triggerId"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::string trigger_id;
|
||||
};
|
||||
|
||||
#endif // __TRIGGER_EVAL_H__
|
||||
36
components/include/generic_rulebase/evaluators/zone_eval.h
Executable file
36
components/include/generic_rulebase/evaluators/zone_eval.h
Executable 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 __ZONE_EVAL_H__
|
||||
#define __ZONE_EVAL_H__
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
|
||||
class ZoneMatcher : public EnvironmentEvaluator<bool>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
ZoneMatcher(const std::vector<std::string> &zones);
|
||||
|
||||
static std::string getName() { return "zoneId"; }
|
||||
|
||||
Maybe<bool, Context::Error> evalVariable() const override;
|
||||
|
||||
static std::string ctx_key;
|
||||
|
||||
private:
|
||||
std::string zone_id;
|
||||
};
|
||||
|
||||
#endif // __ZONE_EVAL_H__
|
||||
44
components/include/generic_rulebase/generic_rulebase.h
Executable file
44
components/include/generic_rulebase/generic_rulebase.h
Executable file
@@ -0,0 +1,44 @@
|
||||
// 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 __GENERIC_RULEBASE_H__
|
||||
#define __GENERIC_RULEBASE_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "i_generic_rulebase.h"
|
||||
#include "i_intelligence_is_v2.h"
|
||||
#include "singleton.h"
|
||||
#include "component.h"
|
||||
|
||||
class GenericRulebase
|
||||
:
|
||||
public Component,
|
||||
Singleton::Provide<I_GenericRulebase>,
|
||||
Singleton::Consume<I_Intelligence_IS_V2>
|
||||
{
|
||||
public:
|
||||
GenericRulebase();
|
||||
~GenericRulebase();
|
||||
|
||||
void preload();
|
||||
|
||||
void init();
|
||||
void fini();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __GENERIC_RULEBASE_H__
|
||||
39
components/include/generic_rulebase/generic_rulebase_context.h
Executable file
39
components/include/generic_rulebase/generic_rulebase_context.h
Executable file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __GENERIC_RULEBASE_CONTEXT_H__
|
||||
#define __GENERIC_RULEBASE_CONTEXT_H__
|
||||
|
||||
#include "rulebase_config.h"
|
||||
#include "context.h"
|
||||
#include "config.h"
|
||||
|
||||
enum class RuleRegistrationState {REGISTERED, UNREGISTERED, UNINITIALIZED};
|
||||
|
||||
class GenericRulebaseContext
|
||||
{
|
||||
public:
|
||||
GenericRulebaseContext() : ctx(), registration_state(RuleRegistrationState::UNINITIALIZED) {}
|
||||
|
||||
void activate(const BasicRuleConfig &rule);
|
||||
|
||||
void activate();
|
||||
|
||||
void deactivate() { if (registration_state == RuleRegistrationState::REGISTERED) ctx.deactivate(); }
|
||||
|
||||
private:
|
||||
Context ctx;
|
||||
RuleRegistrationState registration_state;
|
||||
};
|
||||
|
||||
#endif //__GENERIC_RULEBASE_CONTEXT_H__
|
||||
39
components/include/generic_rulebase/generic_rulebase_utils.h
Executable file
39
components/include/generic_rulebase/generic_rulebase_utils.h
Executable file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved.
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __GENERIC_RULEBASE_UTILS_H__
|
||||
#define __GENERIC_RULEBASE_UTILS_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "debug.h"
|
||||
#include "cereal/archives/json.hpp"
|
||||
|
||||
USE_DEBUG_FLAG(D_RULEBASE_CONFIG);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
parseJSONKey(const std::string &key_name, T &value, cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
try {
|
||||
archive_in(cereal::make_nvp(key_name, value));
|
||||
} catch (const cereal::Exception &e) {
|
||||
dbgDebug(D_RULEBASE_CONFIG)
|
||||
<< "Could not parse the required key. Key: "
|
||||
<< key_name
|
||||
<< ", Error: "
|
||||
<< e.what();
|
||||
}
|
||||
}
|
||||
|
||||
#endif //__GENERIC_RULEBASE_UTILS_H__
|
||||
93
components/include/generic_rulebase/match_query.h
Executable file
93
components/include/generic_rulebase/match_query.h
Executable file
@@ -0,0 +1,93 @@
|
||||
// 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 __MATCH_QUERY_H__
|
||||
#define __MATCH_QUERY_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "cereal/types/string.hpp"
|
||||
#include "cereal/types/vector.hpp"
|
||||
#include "cereal/archives/json.hpp"
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include "c_common/ip_common.h"
|
||||
|
||||
class MatchQuery
|
||||
{
|
||||
public:
|
||||
enum class MatchType { Condition, Operator };
|
||||
enum class Operators { And, Or, None };
|
||||
enum class Conditions { Equals, NotEquals, In, NotIn, Exist, None };
|
||||
enum class StaticKeys
|
||||
{
|
||||
IpAddress,
|
||||
SrcIpAddress,
|
||||
DstIpAddress,
|
||||
SrcPort,
|
||||
ListeningPort,
|
||||
IpProtocol,
|
||||
Domain,
|
||||
NotStatic
|
||||
};
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
MatchType getType() const { return type; }
|
||||
Operators getOperatorType() const { return operator_type; }
|
||||
Conditions getConditionType() const { return condition_type; }
|
||||
const std::string & getKey() const { return key; }
|
||||
const std::set<std::string> & getValue() const { return value; }
|
||||
const std::vector<IPRange> & getIpAddrValue() const { return ip_addr_value; }
|
||||
const std::vector<PortsRange> & getPortValue() const { return port_value; }
|
||||
const std::vector<IpProtoRange> & getProtoValue() const { return ip_proto_value; }
|
||||
const std::vector<MatchQuery> & getItems() const { return items; }
|
||||
std::string getFirstValue() const { return first_value; }
|
||||
bool matchAttributes(const std::unordered_map<std::string, std::set<std::string>> &key_value_pairs) const;
|
||||
bool matchException(const std::string &behaviorKey, const std::string &behaviorValue) const;
|
||||
bool isKeyTypeIp() const;
|
||||
bool isKeyTypePort() const;
|
||||
bool isKeyTypeProtocol() const;
|
||||
bool isKeyTypeDomain() const;
|
||||
bool isKeyTypeSpecificLabel() const;
|
||||
bool isKeyTypeStatic() const;
|
||||
std::set<std::string> getAllKeys() const;
|
||||
|
||||
private:
|
||||
StaticKeys getKeyByName(const std::string &key_type_name);
|
||||
bool matchAttributes(const std::set<std::string> &values) const;
|
||||
bool matchAttributesRegEx(const std::set<std::string> &values) const;
|
||||
bool matchAttributesString(const std::set<std::string> &values) const;
|
||||
bool isRegEx() const;
|
||||
|
||||
MatchType type;
|
||||
Operators operator_type;
|
||||
Conditions condition_type;
|
||||
std::string key;
|
||||
StaticKeys key_type;
|
||||
bool is_specific_label;
|
||||
std::string first_value;
|
||||
std::set<std::string> value;
|
||||
std::set<boost::regex> regex_values;
|
||||
std::vector<IPRange> ip_addr_value;
|
||||
std::vector<PortsRange> port_value;
|
||||
std::vector<IpProtoRange> ip_proto_value;
|
||||
std::vector<MatchQuery> items;
|
||||
};
|
||||
|
||||
#endif // __MATCH_QUERY_H__
|
||||
221
components/include/generic_rulebase/parameters_config.h
Executable file
221
components/include/generic_rulebase/parameters_config.h
Executable file
@@ -0,0 +1,221 @@
|
||||
// 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 __PARAMETERS_CONFIG_H__
|
||||
#define __PARAMETERS_CONFIG_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "cereal/types/string.hpp"
|
||||
#include "cereal/types/vector.hpp"
|
||||
#include "cereal/archives/json.hpp"
|
||||
#include "generic_rulebase/generic_rulebase_utils.h"
|
||||
#include "match_query.h"
|
||||
#include "maybe_res.h"
|
||||
#include "config.h"
|
||||
|
||||
enum class BehaviorKey
|
||||
{
|
||||
ACTION,
|
||||
LOG,
|
||||
SOURCE_IDENTIFIER,
|
||||
HTTP_SOURCE_ID,
|
||||
HTTPS_SOURCE_ID
|
||||
};
|
||||
|
||||
enum class BehaviorValue
|
||||
{
|
||||
REJECT,
|
||||
ACCEPT,
|
||||
IGNORE,
|
||||
DROP,
|
||||
X_FORWARDED_FOR,
|
||||
COOKIE_AOUTH2_PROXY,
|
||||
COOKIE_JSESSIONID
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, BehaviorKey> string_to_behavior_key = {
|
||||
{ "action", BehaviorKey::ACTION },
|
||||
{ "log", BehaviorKey::LOG },
|
||||
{ "sourceIdentifier", BehaviorKey::SOURCE_IDENTIFIER },
|
||||
{ "httpSourceId", BehaviorKey::HTTP_SOURCE_ID },
|
||||
{ "httpsSourceId", BehaviorKey::HTTPS_SOURCE_ID }
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, BehaviorValue> string_to_behavior_val = {
|
||||
{ "Cookie:_oauth2_proxy", BehaviorValue::COOKIE_AOUTH2_PROXY },
|
||||
{ "Cookie:JSESSIONID", BehaviorValue::COOKIE_JSESSIONID },
|
||||
{ "X-Forwarded-For", BehaviorValue::X_FORWARDED_FOR },
|
||||
{ "reject", BehaviorValue::REJECT },
|
||||
{ "accept", BehaviorValue::ACCEPT },
|
||||
{ "ignore", BehaviorValue::IGNORE },
|
||||
{ "drop", BehaviorValue::DROP }
|
||||
};
|
||||
|
||||
class ParameterOverrides
|
||||
{
|
||||
public:
|
||||
class ParsedBehavior
|
||||
{
|
||||
public:
|
||||
void
|
||||
serialize(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseJSONKey<std::string>("log", log, archive_in);
|
||||
}
|
||||
|
||||
const std::string & getParsedBehaviorLog() const { return log; }
|
||||
|
||||
private:
|
||||
std::string log;
|
||||
};
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::vector<ParsedBehavior> & getParsedBehaviors() const { return parsed_behaviors; }
|
||||
|
||||
private:
|
||||
std::vector<ParsedBehavior> parsed_behaviors;
|
||||
};
|
||||
|
||||
class ParameterTrustedSources
|
||||
{
|
||||
public:
|
||||
class SourcesIdentifier
|
||||
{
|
||||
public:
|
||||
|
||||
SourcesIdentifier() = default;
|
||||
|
||||
void
|
||||
serialize(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
parseJSONKey<std::string>("sourceIdentifier", source_identifier, archive_in);
|
||||
parseJSONKey<std::string>("value", value, archive_in);
|
||||
}
|
||||
|
||||
const std::string & getSourceIdentifier() const {return source_identifier; }
|
||||
|
||||
const std::string & getValue() const {return value; }
|
||||
|
||||
private:
|
||||
std::string source_identifier;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
uint getNumOfSources() const { return num_of_sources; }
|
||||
|
||||
const std::vector<SourcesIdentifier> & getSourcesIdentifiers() const { return sources_identidiers; }
|
||||
|
||||
private:
|
||||
uint num_of_sources;
|
||||
std::vector<SourcesIdentifier> sources_identidiers;
|
||||
};
|
||||
|
||||
class ParameterBehavior
|
||||
{
|
||||
public:
|
||||
ParameterBehavior() = default;
|
||||
ParameterBehavior(BehaviorKey &_key, BehaviorValue &_value) : key(_key), value(_value) {}
|
||||
ParameterBehavior(BehaviorKey &&_key, BehaviorValue &&_value)
|
||||
:
|
||||
key(std::move(_key)),
|
||||
value(std::move(_value))
|
||||
{}
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const BehaviorValue & getValue() const { return value; }
|
||||
|
||||
const BehaviorKey & getKey() const { return key; }
|
||||
|
||||
const std::string & getId() const { return id; }
|
||||
|
||||
bool
|
||||
operator<(const ParameterBehavior &other) const {
|
||||
return (key < other.key) || (key == other.key && value < other.value);
|
||||
}
|
||||
|
||||
bool operator==(const ParameterBehavior &other) const { return key == other.key && value == other.value; }
|
||||
|
||||
private:
|
||||
std::string id;
|
||||
BehaviorKey key;
|
||||
BehaviorValue value;
|
||||
};
|
||||
|
||||
class ParameterAntiBot
|
||||
{
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
std::vector<std::string> & getInjected() { return injected; }
|
||||
|
||||
std::vector<std::string> & getValidated() { return validated; }
|
||||
|
||||
private:
|
||||
std::vector<std::string> injected;
|
||||
std::vector<std::string> validated;
|
||||
};
|
||||
|
||||
class ParameterOAS
|
||||
{
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::string & getValue() const { return value; }
|
||||
|
||||
private:
|
||||
std::string value;
|
||||
};
|
||||
|
||||
class ParameterException
|
||||
{
|
||||
public:
|
||||
static void
|
||||
preload()
|
||||
{
|
||||
registerExpectedConfiguration<ParameterException>("rulebase", "exception");
|
||||
registerConfigLoadCb([](){ is_geo_location_exception_exists = is_geo_location_exception_being_loaded; });
|
||||
registerConfigPrepareCb([](){ is_geo_location_exception_being_loaded = false; });
|
||||
}
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
std::set<ParameterBehavior>
|
||||
getBehavior(const std::unordered_map<std::string, std::set<std::string>> &key_value_pairs) const;
|
||||
|
||||
static bool isGeoLocationExceptionExists() { return is_geo_location_exception_exists; }
|
||||
|
||||
private:
|
||||
class MatchBehaviorPair
|
||||
{
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
MatchQuery match;
|
||||
ParameterBehavior behavior;
|
||||
};
|
||||
|
||||
std::vector<MatchBehaviorPair> match_queries;
|
||||
MatchQuery match;
|
||||
ParameterBehavior behavior;
|
||||
static bool is_geo_location_exception_exists;
|
||||
static bool is_geo_location_exception_being_loaded;
|
||||
};
|
||||
|
||||
#endif //__PARAMETERS_CONFIG_H__
|
||||
167
components/include/generic_rulebase/rulebase_config.h
Executable file
167
components/include/generic_rulebase/rulebase_config.h
Executable file
@@ -0,0 +1,167 @@
|
||||
// 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 __RULEBASE_CONFIG_H__
|
||||
#define __RULEBASE_CONFIG_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "generic_rulebase/generic_rulebase_utils.h"
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "cereal/types/string.hpp"
|
||||
#include "cereal/types/vector.hpp"
|
||||
#include "cereal/archives/json.hpp"
|
||||
#include "i_environment.h"
|
||||
#include "singleton.h"
|
||||
#include "maybe_res.h"
|
||||
#include "config.h"
|
||||
|
||||
using GenericConfigId = std::string;
|
||||
|
||||
class RulePractice
|
||||
{
|
||||
public:
|
||||
RulePractice() = default;
|
||||
|
||||
RulePractice(GenericConfigId &_id, std::string &_name) : practice_id(_id), practice_name(_name) {};
|
||||
|
||||
void
|
||||
serialize(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
parseJSONKey<GenericConfigId>("practiceId", practice_id, ar);
|
||||
parseJSONKey<std::string>("practiceName", practice_name, ar);
|
||||
}
|
||||
|
||||
const GenericConfigId getId() const { return practice_id; }
|
||||
|
||||
const std::string getName() const { return practice_name; }
|
||||
|
||||
bool
|
||||
operator==(const RulePractice &other) const
|
||||
{
|
||||
return practice_id == other.getId() && practice_name == other.getName();
|
||||
}
|
||||
|
||||
private:
|
||||
GenericConfigId practice_id;
|
||||
std::string practice_name;
|
||||
};
|
||||
|
||||
class RuleTrigger
|
||||
{
|
||||
public:
|
||||
void
|
||||
serialize(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
parseJSONKey<GenericConfigId>("triggerId", trigger_id, ar);
|
||||
parseJSONKey<std::string>("triggerType", trigger_type, ar);
|
||||
parseJSONKey<std::string>("triggerName", trigger_name, ar);
|
||||
}
|
||||
|
||||
const GenericConfigId getId() const { return trigger_id; }
|
||||
|
||||
const std::string getType() const { return trigger_type; }
|
||||
|
||||
const std::string getName() const { return trigger_name; }
|
||||
|
||||
private:
|
||||
GenericConfigId trigger_id;
|
||||
std::string trigger_type;
|
||||
std::string trigger_name;
|
||||
};
|
||||
|
||||
class RuleParameter
|
||||
{
|
||||
public:
|
||||
void
|
||||
serialize(cereal::JSONInputArchive &ar)
|
||||
{
|
||||
parseJSONKey<GenericConfigId>("parameterId", parameter_id, ar);
|
||||
parseJSONKey<std::string>("parameterType", parameter_type, ar);
|
||||
parseJSONKey<std::string>("parameterName", parameter_name, ar);
|
||||
}
|
||||
|
||||
const GenericConfigId getId() const { return parameter_id; }
|
||||
|
||||
const std::string getType() const { return parameter_type; }
|
||||
|
||||
const std::string getName() const { return parameter_name; }
|
||||
|
||||
private:
|
||||
GenericConfigId parameter_id;
|
||||
std::string parameter_type;
|
||||
std::string parameter_name;
|
||||
};
|
||||
|
||||
class BasicRuleConfig
|
||||
{
|
||||
public:
|
||||
static void
|
||||
preload()
|
||||
{
|
||||
registerExpectedConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
|
||||
registerExpectedSetting<std::vector<BasicRuleConfig>>("rulebase", "rulesConfig");
|
||||
registerConfigLoadCb(BasicRuleConfig::updateCountMetric);
|
||||
registerConfigPrepareCb([](){ BasicRuleConfig::assets_ids_aggregation.clear(); });
|
||||
}
|
||||
|
||||
void load(cereal::JSONInputArchive &ar);
|
||||
|
||||
static void updateCountMetric();
|
||||
|
||||
bool isPracticeActive(const GenericConfigId &practice_id) const;
|
||||
|
||||
bool isTriggerActive(const GenericConfigId &trigger_id) const;
|
||||
|
||||
bool isParameterActive(const GenericConfigId ¶meter_id) const;
|
||||
|
||||
uint8_t getPriority() const { return priority; }
|
||||
|
||||
const GenericConfigId & getRuleId() const { return rule_id; }
|
||||
|
||||
const std::string & getRuleName() const { return rule_name; }
|
||||
|
||||
const GenericConfigId & getAssetId() const { return asset_id; }
|
||||
|
||||
const std::string & getAssetName() const { return asset_name; }
|
||||
|
||||
const GenericConfigId & getZoneId() const { return zone_id; }
|
||||
|
||||
const std::string & getZoneName() const { return zone_name; }
|
||||
|
||||
const std::vector<RulePractice> & getPractices() const { return practices; }
|
||||
|
||||
const std::vector<RuleTrigger> & getTriggers() const { return triggers; }
|
||||
|
||||
const std::vector<RuleParameter> & getParameters() const { return parameters; }
|
||||
|
||||
private:
|
||||
uint8_t priority = 0;
|
||||
GenericConfigId rule_id = "";
|
||||
std::string rule_name;
|
||||
GenericConfigId asset_id;
|
||||
std::string asset_name;
|
||||
GenericConfigId zone_id;
|
||||
std::string zone_name;
|
||||
std::vector<RulePractice> practices;
|
||||
std::vector<RuleTrigger> triggers;
|
||||
std::vector<RuleParameter> parameters;
|
||||
|
||||
static std::set<std::string> assets_ids;
|
||||
static std::set<std::string> assets_ids_aggregation;
|
||||
};
|
||||
|
||||
#endif // __RULEBASE_CONFIG_H__
|
||||
174
components/include/generic_rulebase/triggers_config.h
Executable file
174
components/include/generic_rulebase/triggers_config.h
Executable file
@@ -0,0 +1,174 @@
|
||||
// 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 __TRIGGERS_CONFIG_H__
|
||||
#define __TRIGGERS_CONFIG_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "environment/evaluator_templates.h"
|
||||
#include "cereal/types/string.hpp"
|
||||
#include "cereal/types/vector.hpp"
|
||||
#include "cereal/archives/json.hpp"
|
||||
#include "i_environment.h"
|
||||
#include "i_logging.h"
|
||||
#include "singleton.h"
|
||||
#include "maybe_res.h"
|
||||
#include "config.h"
|
||||
#include "log_generator.h"
|
||||
#include "generic_rulebase_utils.h"
|
||||
|
||||
class WebTriggerConf
|
||||
{
|
||||
public:
|
||||
WebTriggerConf();
|
||||
WebTriggerConf(const std::string &title, const std::string &body, uint code);
|
||||
|
||||
static void
|
||||
preload()
|
||||
{
|
||||
registerExpectedConfiguration<WebTriggerConf>("rulebase", "webUserResponse");
|
||||
}
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool operator==(const WebTriggerConf &other) const;
|
||||
|
||||
uint getResponseCode() const { return response_code; }
|
||||
|
||||
const std::string & getResponseTitle() const { return response_title; }
|
||||
|
||||
const std::string & getResponseBody() const { return response_body; }
|
||||
|
||||
const std::string & getDetailsLevel() const { return details_level; }
|
||||
|
||||
const std::string & getRedirectURL() const { return redirect_url; }
|
||||
|
||||
bool getAddEventId() const { return add_event_id_to_header; }
|
||||
|
||||
static WebTriggerConf default_trigger_conf;
|
||||
|
||||
private:
|
||||
std::string response_title;
|
||||
std::string details_level;
|
||||
std::string response_body;
|
||||
std::string redirect_url;
|
||||
uint response_code;
|
||||
bool add_event_id_to_header = false;
|
||||
};
|
||||
|
||||
class LogTriggerConf : Singleton::Consume<I_Logging>
|
||||
{
|
||||
public:
|
||||
enum class SecurityType { AccessControl, ThreatPrevention, Compliance, COUNT };
|
||||
enum class extendLoggingSeverity { None, High, Critical };
|
||||
|
||||
enum class WebLogFields {
|
||||
webBody,
|
||||
webHeaders,
|
||||
webRequests,
|
||||
webUrlPath,
|
||||
webUrlQuery,
|
||||
responseBody,
|
||||
responseCode,
|
||||
COUNT
|
||||
};
|
||||
|
||||
LogTriggerConf() {}
|
||||
|
||||
LogTriggerConf(std::string trigger_name, bool log_detect, bool log_prevent);
|
||||
|
||||
static void
|
||||
preload()
|
||||
{
|
||||
registerExpectedConfiguration<LogTriggerConf>("rulebase", "log");
|
||||
}
|
||||
|
||||
template <typename ...Tags>
|
||||
LogGen
|
||||
operator()(
|
||||
const std::string &title,
|
||||
SecurityType security,
|
||||
ReportIS::Severity severity,
|
||||
ReportIS::Priority priority,
|
||||
bool is_action_drop_or_prevent,
|
||||
Tags ...tags) const
|
||||
{
|
||||
return LogGen(
|
||||
title,
|
||||
ReportIS::Level::LOG,
|
||||
ReportIS::Audience::SECURITY,
|
||||
severity,
|
||||
priority,
|
||||
std::forward<Tags>(tags)...,
|
||||
getStreams(security, is_action_drop_or_prevent),
|
||||
getEnrechments(security)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename ...Tags>
|
||||
LogGen
|
||||
operator()(const std::string &title, SecurityType security, bool is_action_drop_or_prevent, Tags ...tags) const
|
||||
{
|
||||
return (*this)(
|
||||
title,
|
||||
security,
|
||||
getSeverity(is_action_drop_or_prevent),
|
||||
getPriority(is_action_drop_or_prevent),
|
||||
is_action_drop_or_prevent,
|
||||
std::forward<Tags>(tags)...
|
||||
);
|
||||
}
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool isWebLogFieldActive(WebLogFields log_field) const { return log_web_fields.isSet(log_field); }
|
||||
|
||||
bool isLogStreamActive(ReportIS::StreamType stream_type) const { return active_streams.isSet(stream_type); }
|
||||
|
||||
bool isPreventLogActive(SecurityType security_type) const { return should_log_on_prevent.isSet(security_type); }
|
||||
|
||||
bool isDetectLogActive(SecurityType security_type) const { return should_log_on_detect.isSet(security_type); }
|
||||
|
||||
bool isLogGeoLocationActive(SecurityType security_type) const { return log_geo_location.isSet(security_type); }
|
||||
|
||||
extendLoggingSeverity getExtendLoggingSeverity() const { return extend_logging_severity; }
|
||||
|
||||
const std::string & getVerbosity() const { return verbosity; }
|
||||
const std::string & getName() const { return name; }
|
||||
|
||||
const std::string & getUrlForSyslog() const { return url_for_syslog; }
|
||||
const std::string & getUrlForCef() const { return url_for_cef; }
|
||||
|
||||
private:
|
||||
ReportIS::Severity getSeverity(bool is_action_drop_or_prevent) const;
|
||||
ReportIS::Priority getPriority(bool is_action_drop_or_prevent) const;
|
||||
|
||||
Flags<ReportIS::StreamType> getStreams(SecurityType security_type, bool is_action_drop_or_prevent) const;
|
||||
Flags<ReportIS::Enreachments> getEnrechments(SecurityType security_type) const;
|
||||
|
||||
std::string name;
|
||||
std::string verbosity;
|
||||
std::string url_for_syslog = "";
|
||||
std::string url_for_cef = "";
|
||||
Flags<ReportIS::StreamType> active_streams;
|
||||
Flags<SecurityType> should_log_on_detect;
|
||||
Flags<SecurityType> should_log_on_prevent;
|
||||
Flags<SecurityType> log_geo_location;
|
||||
Flags<WebLogFields> log_web_fields;
|
||||
extendLoggingSeverity extend_logging_severity = extendLoggingSeverity::None;
|
||||
bool should_format_output = false;
|
||||
};
|
||||
|
||||
#endif //__TRIGGERS_CONFIG_H__
|
||||
55
components/include/generic_rulebase/zone.h
Executable file
55
components/include/generic_rulebase/zone.h
Executable file
@@ -0,0 +1,55 @@
|
||||
// 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 __ZONE_H__
|
||||
#define __ZONE_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "generic_rulebase_context.h"
|
||||
#include "match_query.h"
|
||||
#include "i_environment.h"
|
||||
#include "i_intelligence_is_v2.h"
|
||||
#include "asset.h"
|
||||
|
||||
class Zone : Singleton::Consume<I_Intelligence_IS_V2>, Singleton::Consume<I_Environment>
|
||||
{
|
||||
using AttrData = std::unordered_map<std::string, std::set<std::string>>;
|
||||
|
||||
public:
|
||||
enum class Direction { To, From, Bidirectional };
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
bool contains(const Asset &asset);
|
||||
|
||||
GenericConfigId getId() const { return zone_id; }
|
||||
const std::string & getName() const { return zone_name; }
|
||||
const std::vector<std::pair<Direction, GenericConfigId>> & getAdjacentZones() const { return adjacent_zones; }
|
||||
const MatchQuery & getMatchQuery() const { return match_query; }
|
||||
bool isAnyZone() const { return is_any; }
|
||||
|
||||
private:
|
||||
bool matchAttributes(const AttrData &data);
|
||||
|
||||
GenericConfigId zone_id;
|
||||
std::string zone_name;
|
||||
std::vector<std::pair<Direction, GenericConfigId>> adjacent_zones;
|
||||
MatchQuery match_query;
|
||||
bool is_any;
|
||||
};
|
||||
|
||||
#endif // __ZONE_H__
|
||||
53
components/include/generic_rulebase/zones_config.h
Executable file
53
components/include/generic_rulebase/zones_config.h
Executable file
@@ -0,0 +1,53 @@
|
||||
// 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 __ZONES_CONFIG_H__
|
||||
#define __ZONES_CONFIG_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "generic_rulebase_context.h"
|
||||
#include "match_query.h"
|
||||
#include "i_generic_rulebase.h"
|
||||
#include "zone.h"
|
||||
|
||||
class Zones
|
||||
{
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in)
|
||||
{
|
||||
cereal::load(archive_in, zones);
|
||||
}
|
||||
|
||||
const std::vector<Zone> & getZones() const { return zones; }
|
||||
|
||||
std::vector<Zone> zones;
|
||||
};
|
||||
|
||||
class ZonesConfig : Singleton::Consume<I_GenericRulebase>
|
||||
{
|
||||
public:
|
||||
static void preload();
|
||||
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
|
||||
const std::vector<Zone> & getZones() const { return zones; }
|
||||
|
||||
private:
|
||||
std::vector<Zone> zones;
|
||||
};
|
||||
|
||||
#endif //__ZONES_CONFIG_H__
|
||||
43
components/include/gradual_deployment.h
Normal file
43
components/include/gradual_deployment.h
Normal file
@@ -0,0 +1,43 @@
|
||||
// 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 __GRADUAL_DEPLOYMENT_H__
|
||||
#define __GRADUAL_DEPLOYMENT_H__
|
||||
|
||||
#include "i_gradual_deployment.h"
|
||||
|
||||
#include "singleton.h"
|
||||
#include "i_rest_api.h"
|
||||
#include "i_table.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "component.h"
|
||||
|
||||
class GradualDeployment
|
||||
:
|
||||
public Component,
|
||||
Singleton::Provide<I_GradualDeployment>,
|
||||
Singleton::Consume<I_RestApi>,
|
||||
Singleton::Consume<I_MainLoop>
|
||||
{
|
||||
public:
|
||||
GradualDeployment();
|
||||
~GradualDeployment();
|
||||
|
||||
void init();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __GRADUAL_DEPLOYMENT_H__
|
||||
45
components/include/health_check_manager.h
Executable file
45
components/include/health_check_manager.h
Executable file
@@ -0,0 +1,45 @@
|
||||
// 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 __HEALTH_CHECK_MANAGER_H__
|
||||
#define __HEALTH_CHECK_MANAGER_H__
|
||||
|
||||
#include "singleton.h"
|
||||
#include "i_health_check_manager.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "i_rest_api.h"
|
||||
#include "component.h"
|
||||
#include "i_messaging.h"
|
||||
#include "i_environment.h"
|
||||
|
||||
class HealthCheckManager
|
||||
:
|
||||
public Component,
|
||||
Singleton::Provide<I_Health_Check_Manager>,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_RestApi>,
|
||||
Singleton::Consume<I_Messaging>,
|
||||
Singleton::Consume<I_Environment>
|
||||
{
|
||||
public:
|
||||
HealthCheckManager();
|
||||
~HealthCheckManager();
|
||||
|
||||
void init() override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __HEALTH_CHECK_MANAGER_H__
|
||||
44
components/include/health_checker.h
Executable file
44
components/include/health_checker.h
Executable file
@@ -0,0 +1,44 @@
|
||||
// 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 __HEALTH_CHECKER_H__
|
||||
#define __HEALTH_CHECKER_H__
|
||||
|
||||
#include "singleton.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "i_socket_is.h"
|
||||
#include "i_health_check_manager.h"
|
||||
#include "component.h"
|
||||
|
||||
class HealthChecker
|
||||
:
|
||||
public Component,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_Socket>,
|
||||
Singleton::Consume<I_Health_Check_Manager>
|
||||
{
|
||||
public:
|
||||
HealthChecker();
|
||||
~HealthChecker();
|
||||
|
||||
void init() override;
|
||||
void fini() override;
|
||||
|
||||
void preload() override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __HEALTH_CHECKER_H__
|
||||
69
components/include/http_event_impl/filter_verdict.h
Executable file
69
components/include/http_event_impl/filter_verdict.h
Executable file
@@ -0,0 +1,69 @@
|
||||
// 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 __FILTER_VERDICT_H__
|
||||
#define __FILTER_VERDICT_H__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "maybe_res.h"
|
||||
#include "i_http_event_impl.h"
|
||||
|
||||
class FilterVerdict
|
||||
{
|
||||
public:
|
||||
FilterVerdict(ngx_http_cp_verdict_e _verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT)
|
||||
:
|
||||
verdict(_verdict)
|
||||
{}
|
||||
|
||||
FilterVerdict(const EventVerdict &_verdict, ModifiedChunkIndex _event_idx = -1)
|
||||
:
|
||||
verdict(_verdict.getVerdict())
|
||||
{
|
||||
if (verdict == ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INJECT) {
|
||||
addModifications(_verdict.getModifications(), _event_idx);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
addModifications(const FilterVerdict &other)
|
||||
{
|
||||
if (other.verdict != ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INJECT) return;
|
||||
|
||||
modifications.insert(modifications.end(), other.modifications.begin(), other.modifications.end());
|
||||
total_modifications += other.total_modifications;
|
||||
}
|
||||
|
||||
void
|
||||
addModifications(
|
||||
const ModificationList &mods,
|
||||
ModifiedChunkIndex _event_idx,
|
||||
ngx_http_cp_verdict_e alt_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT)
|
||||
{
|
||||
total_modifications += mods.size();
|
||||
modifications.push_back(EventModifications(_event_idx, mods));
|
||||
if (alt_verdict != ngx_http_cp_verdict_e::TRAFFIC_VERDICT_IRRELEVANT) verdict = alt_verdict;
|
||||
}
|
||||
|
||||
uint getModificationsAmount() const { return total_modifications; }
|
||||
ngx_http_cp_verdict_e getVerdict() const { return verdict; }
|
||||
const std::vector<EventModifications> & getModifications() const { return modifications; }
|
||||
|
||||
private:
|
||||
ngx_http_cp_verdict_e verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
|
||||
std::vector<EventModifications> modifications;
|
||||
uint total_modifications = 0;
|
||||
};
|
||||
|
||||
#endif // __FILTER_VERDICT_H__
|
||||
387
components/include/http_event_impl/i_http_event_impl.h
Executable file
387
components/include/http_event_impl/i_http_event_impl.h
Executable file
@@ -0,0 +1,387 @@
|
||||
// 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 __I_HTTP_EVENT_IMPL_H__
|
||||
#define __I_HTTP_EVENT_IMPL_H__
|
||||
|
||||
#ifndef __HTTP_INSPECTION_EVENTS_H__
|
||||
#error i_http_event_impl.h should not be included directly!
|
||||
#endif //__HTTP_INSPECTION_EVENTS_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "debug.h"
|
||||
#include "buffer.h"
|
||||
#include "http_transaction_data.h"
|
||||
#include "nginx_attachment_common.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_HTTP_MANAGER);
|
||||
|
||||
using ModificationType = ngx_http_modification_type_e;
|
||||
using ModificationPosition = ngx_http_cp_inject_pos_t;
|
||||
|
||||
static const ModificationPosition injection_pos_irrelevant = INJECT_POS_IRRELEVANT;
|
||||
|
||||
template <typename TMod>
|
||||
class Modification
|
||||
{
|
||||
public:
|
||||
Modification(const TMod &mod, ModificationType mod_type)
|
||||
:
|
||||
Modification(mod, mod_type, injection_pos_irrelevant)
|
||||
{}
|
||||
|
||||
Modification(const TMod &mod, ModificationType mod_type, ModificationPosition mod_position)
|
||||
:
|
||||
modification(mod),
|
||||
type(mod_type),
|
||||
position(mod_position)
|
||||
{
|
||||
dbgAssert(mod_type != ModificationType::APPEND || position == injection_pos_irrelevant)
|
||||
<< "Injection position is not applicable to a modification of type \"Append\"";
|
||||
|
||||
dbgAssert(mod_type != ModificationType::INJECT || position >= 0)
|
||||
<< "Invalid injection position: must be non-negative. Position: "
|
||||
<< position;
|
||||
}
|
||||
|
||||
ModificationPosition getModificationPosition() const { return position; }
|
||||
ModificationType getModificationType() const { return type; }
|
||||
const TMod & getModification() const { return modification; }
|
||||
|
||||
private:
|
||||
TMod modification;
|
||||
ModificationType type;
|
||||
ModificationPosition position;
|
||||
};
|
||||
|
||||
using ModifiedChunkIndex = int;
|
||||
using ModificationBuffer = std::tuple<ModificationPosition, ModificationType, Buffer>;
|
||||
using ModificationList = std::vector<ModificationBuffer>;
|
||||
using EventModifications = std::pair<ModifiedChunkIndex, ModificationList>;
|
||||
|
||||
template <typename TMod>
|
||||
class I_ModifiableContent
|
||||
{
|
||||
public:
|
||||
virtual Maybe<void> modify(const Modification<TMod> &mod) = 0;
|
||||
|
||||
virtual ModificationList getModificationList() const = 0;
|
||||
|
||||
protected:
|
||||
virtual ~I_ModifiableContent() {}
|
||||
};
|
||||
|
||||
using HeaderKey = std::string;
|
||||
using HeaderModification = std::pair<std::pair<ModificationPosition, HeaderKey>, Buffer>;
|
||||
|
||||
class HttpHeaderModification : I_ModifiableContent<HeaderModification>
|
||||
{
|
||||
public:
|
||||
Maybe<void>
|
||||
appendHeader(const HeaderKey &key, const Buffer &value)
|
||||
{
|
||||
return modify(
|
||||
Modification<HeaderModification>(
|
||||
HeaderModification({ { injection_pos_irrelevant, key }, value }),
|
||||
ModificationType::APPEND
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
injectValue(ModificationPosition position, const Buffer &data)
|
||||
{
|
||||
return modify(
|
||||
Modification<HeaderModification>(
|
||||
HeaderModification({ { position, HeaderKey() }, data }),
|
||||
ModificationType::INJECT,
|
||||
position
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ModificationList
|
||||
getModificationList() const override
|
||||
{
|
||||
ModificationList modification_list;
|
||||
|
||||
for (const auto &modification : headers_to_append) {
|
||||
modification_list.emplace_back(injection_pos_irrelevant, ModificationType::APPEND, modification.first);
|
||||
modification_list.emplace_back(injection_pos_irrelevant, ModificationType::APPEND, modification.second);
|
||||
}
|
||||
for (const auto &modification : header_injections) {
|
||||
modification_list.emplace_back(modification.first, ModificationType::INJECT, modification.second);
|
||||
}
|
||||
|
||||
return modification_list;
|
||||
}
|
||||
|
||||
private:
|
||||
Maybe<void>
|
||||
modify(const Modification<HeaderModification> &mod) override
|
||||
{
|
||||
auto modification_type = mod.getModificationType();
|
||||
switch (modification_type) {
|
||||
case ModificationType::APPEND: {
|
||||
const HeaderKey &appended_header_key = mod.getModification().first.second;
|
||||
auto iterator = headers_to_append.find(appended_header_key);
|
||||
if (iterator != headers_to_append.end()) {
|
||||
return
|
||||
genError(
|
||||
"Append modification with provided header key already exists. Header key: \"" +
|
||||
appended_header_key +
|
||||
"\""
|
||||
);
|
||||
}
|
||||
|
||||
headers_to_append.emplace(appended_header_key, mod.getModification().second);
|
||||
break;
|
||||
}
|
||||
case ModificationType::INJECT: {
|
||||
auto iterator = header_injections.find(mod.getModificationPosition());
|
||||
if (iterator != header_injections.end()) {
|
||||
return genError("Inject modification with provided position already exists");
|
||||
}
|
||||
|
||||
header_injections.emplace(mod.getModificationPosition(), mod.getModification().second);
|
||||
break;
|
||||
}
|
||||
case ModificationType::REPLACE: {
|
||||
// future support to pass new Content-Length
|
||||
dbgWarning(D_HTTP_MANAGER) << "Replace modification is not yet supported";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dbgAssert(false)
|
||||
<< "Unknown type of ModificationType: "
|
||||
<< static_cast<int>(modification_type);
|
||||
}
|
||||
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<HeaderKey, Buffer> headers_to_append;
|
||||
std::map<ModificationPosition, Buffer> header_injections;
|
||||
};
|
||||
|
||||
class HttpHeader
|
||||
{
|
||||
public:
|
||||
HttpHeader() = default;
|
||||
HttpHeader(const Buffer &_key, const Buffer &_value, uint8_t _header_index, bool _is_last_header = false)
|
||||
:
|
||||
key(_key),
|
||||
value(_value),
|
||||
is_last_header(_is_last_header),
|
||||
header_index(_header_index)
|
||||
{
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START - sync functions, can only be tested once the sync module exists
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
ar(
|
||||
key,
|
||||
value,
|
||||
is_last_header,
|
||||
header_index
|
||||
);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
load(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
key,
|
||||
value,
|
||||
is_last_header,
|
||||
header_index
|
||||
);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
print(std::ostream &out_stream) const
|
||||
{
|
||||
out_stream
|
||||
<< "'"
|
||||
<< std::dumpHex(key)
|
||||
<< "': '"
|
||||
<< std::dumpHex(value)
|
||||
<< "' (Index: "
|
||||
<< std::to_string(header_index)
|
||||
<< ", Is last header: "
|
||||
<< (is_last_header ? "True" : "False")
|
||||
<< ")";
|
||||
}
|
||||
|
||||
const Buffer & getKey() const { return key; }
|
||||
const Buffer & getValue() const { return value; }
|
||||
|
||||
bool isLastHeader() const { return is_last_header; }
|
||||
uint8_t getHeaderIndex() const { return header_index; }
|
||||
|
||||
private:
|
||||
Buffer key;
|
||||
Buffer value;
|
||||
bool is_last_header = false;
|
||||
uint8_t header_index = 0;
|
||||
};
|
||||
|
||||
using BodyModification = Buffer;
|
||||
class HttpBodyModification : I_ModifiableContent<BodyModification>
|
||||
{
|
||||
public:
|
||||
Maybe<void>
|
||||
inject(ModificationPosition position, const Buffer &data)
|
||||
{
|
||||
return modify(
|
||||
Modification<BodyModification>(
|
||||
std::move(data),
|
||||
ModificationType::INJECT,
|
||||
position
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ModificationList
|
||||
getModificationList() const override
|
||||
{
|
||||
ModificationList injected_data;
|
||||
for (const auto &injection : modifications) {
|
||||
auto injection_buffer = injection.second;
|
||||
injected_data.emplace_back(injection.first, ModificationType::INJECT, injection_buffer);
|
||||
}
|
||||
return injected_data;
|
||||
}
|
||||
|
||||
private:
|
||||
Maybe<void>
|
||||
modify(const Modification<BodyModification> &mod) override
|
||||
{
|
||||
if (modifications.find(mod.getModificationPosition()) != modifications.end()) {
|
||||
return genError("Modification at the provided index already exists");
|
||||
}
|
||||
modifications[mod.getModificationPosition()] = mod.getModification();
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
std::map<ModificationPosition, Buffer> modifications;
|
||||
};
|
||||
|
||||
class HttpBody
|
||||
{
|
||||
public:
|
||||
HttpBody()
|
||||
:
|
||||
data(),
|
||||
previous_chunked_data(),
|
||||
is_last_chunk(false),
|
||||
body_chunk_index(0)
|
||||
{}
|
||||
|
||||
HttpBody(const Buffer &body_data, bool _is_last_chunk, uint8_t _body_chunk_index)
|
||||
:
|
||||
data(body_data),
|
||||
previous_chunked_data(),
|
||||
is_last_chunk(_is_last_chunk),
|
||||
body_chunk_index(_body_chunk_index)
|
||||
{}
|
||||
|
||||
// LCOV_EXCL_START - sync functions, can only be tested once the sync module exists
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
ar(
|
||||
data,
|
||||
previous_chunked_data,
|
||||
is_last_chunk,
|
||||
body_chunk_index
|
||||
);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
load(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
data,
|
||||
previous_chunked_data,
|
||||
is_last_chunk,
|
||||
body_chunk_index
|
||||
);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
print(std::ostream &out_stream) const
|
||||
{
|
||||
out_stream
|
||||
<< "'"
|
||||
<< std::dumpHex(data)
|
||||
<< "' (Index: "
|
||||
<< std::to_string(body_chunk_index)
|
||||
<< ", Is last chunk: "
|
||||
<< (is_last_chunk ? "True" : "False")
|
||||
<< ")";
|
||||
}
|
||||
|
||||
const Buffer & getData() const { return data; }
|
||||
const Buffer & getPreviousChunkedData() const { return previous_chunked_data; }
|
||||
void setPreviousChunkedData(const Buffer &prev_body_data) { previous_chunked_data = prev_body_data; }
|
||||
|
||||
bool isLastChunk() const { return is_last_chunk; }
|
||||
uint8_t getBodyChunkIndex() const { return body_chunk_index; }
|
||||
|
||||
private:
|
||||
Buffer data;
|
||||
Buffer previous_chunked_data;
|
||||
bool is_last_chunk;
|
||||
uint8_t body_chunk_index;
|
||||
};
|
||||
|
||||
class EventVerdict
|
||||
{
|
||||
public:
|
||||
EventVerdict() = default;
|
||||
|
||||
EventVerdict(ngx_http_cp_verdict_e event_verdict) : modifications(), verdict(event_verdict) {}
|
||||
|
||||
EventVerdict(const ModificationList &mods) : modifications(mods) {}
|
||||
|
||||
EventVerdict(const ModificationList &mods, ngx_http_cp_verdict_e event_verdict) :
|
||||
modifications(mods),
|
||||
verdict(event_verdict)
|
||||
{}
|
||||
|
||||
// LCOV_EXCL_START - sync functions, can only be tested once the sync module exists
|
||||
template <typename T> void serialize(T &ar, uint) { ar(verdict); }
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
const ModificationList & getModifications() const { return modifications; }
|
||||
ngx_http_cp_verdict_e getVerdict() const { return verdict; }
|
||||
|
||||
private:
|
||||
ModificationList modifications;
|
||||
ngx_http_cp_verdict_e verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
|
||||
};
|
||||
|
||||
#endif // __I_HTTP_EVENT_IMPL_H__
|
||||
186
components/include/http_inspection_events.h
Executable file
186
components/include/http_inspection_events.h
Executable file
@@ -0,0 +1,186 @@
|
||||
// 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_INSPECTION_EVENTS_H__
|
||||
#define __HTTP_INSPECTION_EVENTS_H__
|
||||
|
||||
#include "debug.h"
|
||||
#include "event.h"
|
||||
|
||||
#include "http_event_impl/filter_verdict.h"
|
||||
#include "http_event_impl/i_http_event_impl.h"
|
||||
|
||||
using ResponseCode = uint16_t;
|
||||
|
||||
class HttpRequestHeaderEvent : public Event<HttpRequestHeaderEvent, EventVerdict>
|
||||
{
|
||||
public:
|
||||
HttpRequestHeaderEvent(const HttpHeader &header) : req_header(header) {}
|
||||
|
||||
const Buffer & getKey() const { return req_header.getKey(); }
|
||||
const Buffer & getValue() const { return req_header.getValue(); }
|
||||
bool isLastHeader() const { return req_header.isLastHeader(); }
|
||||
uint8_t getHeaderIndex() const { return req_header.getHeaderIndex(); }
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
req_header.save(ar);
|
||||
}
|
||||
|
||||
void print(std::ostream &out_stream) const { req_header.print(out_stream); }
|
||||
|
||||
private:
|
||||
const HttpHeader &req_header;
|
||||
};
|
||||
|
||||
class HttpResponseHeaderEvent: public Event<HttpResponseHeaderEvent, EventVerdict>
|
||||
{
|
||||
public:
|
||||
HttpResponseHeaderEvent(const HttpHeader &header) : res_header(header) {}
|
||||
|
||||
const Buffer & getKey() const { return res_header.getKey(); }
|
||||
const Buffer & getValue() const { return res_header.getValue(); }
|
||||
bool isLastHeader() const { return res_header.isLastHeader(); }
|
||||
uint8_t getHeaderIndex() const { return res_header.getHeaderIndex(); }
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
res_header.save(ar);
|
||||
}
|
||||
|
||||
void print(std::ostream &out_stream) const { res_header.print(out_stream); }
|
||||
|
||||
private:
|
||||
const HttpHeader &res_header;
|
||||
};
|
||||
|
||||
class HttpRequestBodyEvent: public Event<HttpRequestBodyEvent, EventVerdict>
|
||||
{
|
||||
public:
|
||||
HttpRequestBodyEvent(const HttpBody &body, const Buffer &previous_chunked_data)
|
||||
:
|
||||
req_body(body),
|
||||
prev_chunked_data(previous_chunked_data)
|
||||
{}
|
||||
|
||||
const Buffer & getData() const { return req_body.getData(); }
|
||||
const Buffer & getPreviousChunkedData() const { return prev_chunked_data; }
|
||||
bool isLastChunk() const { return req_body.isLastChunk(); }
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
req_body.save(ar);
|
||||
}
|
||||
|
||||
void print(std::ostream &out_stream) const { req_body.print(out_stream); }
|
||||
|
||||
private:
|
||||
const HttpBody &req_body;
|
||||
const Buffer &prev_chunked_data;
|
||||
};
|
||||
|
||||
class HttpResponseBodyEvent: public Event<HttpResponseBodyEvent, EventVerdict>
|
||||
{
|
||||
public:
|
||||
HttpResponseBodyEvent(const HttpBody &body, const Buffer &previous_chunked_data)
|
||||
:
|
||||
res_body(body),
|
||||
prev_chunked_data(previous_chunked_data)
|
||||
{}
|
||||
|
||||
const Buffer & getData() const { return res_body.getData(); }
|
||||
const Buffer & getPreviousChunkedData() const { return prev_chunked_data; }
|
||||
bool isLastChunk() const { return res_body.isLastChunk(); }
|
||||
uint8_t getBodyChunkIndex() const { return res_body.getBodyChunkIndex(); }
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
res_body.save(ar);
|
||||
}
|
||||
|
||||
void print(std::ostream &out_stream) const { res_body.print(out_stream); }
|
||||
|
||||
private:
|
||||
const HttpBody &res_body;
|
||||
const Buffer &prev_chunked_data;
|
||||
};
|
||||
|
||||
|
||||
class NewHttpTransactionEvent : public Event<NewHttpTransactionEvent, EventVerdict>
|
||||
{
|
||||
public:
|
||||
NewHttpTransactionEvent(const HttpTransactionData &event_data) : http_transaction_event_data(event_data) {}
|
||||
|
||||
const IPAddr & getSourceIP() const { return http_transaction_event_data.getSourceIP(); }
|
||||
uint16_t getSourcePort() const { return http_transaction_event_data.getSourcePort(); }
|
||||
const IPAddr & getListeningIP() const { return http_transaction_event_data.getListeningIP(); }
|
||||
uint16_t getListeningPort() const { return http_transaction_event_data.getListeningPort(); }
|
||||
const std::string & getDestinationHost() const { return http_transaction_event_data.getDestinationHost(); }
|
||||
const std::string & getHttpProtocol() const { return http_transaction_event_data.getHttpProtocol(); }
|
||||
const std::string & getURI() const { return http_transaction_event_data.getURI(); }
|
||||
const std::string & getHttpMethod() const { return http_transaction_event_data.getHttpMethod(); }
|
||||
|
||||
void print(std::ostream &out_stream) const { http_transaction_event_data.print(out_stream); }
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
http_transaction_event_data.save(ar);
|
||||
}
|
||||
|
||||
private:
|
||||
const HttpTransactionData &http_transaction_event_data;
|
||||
};
|
||||
|
||||
class ResponseCodeEvent : public Event<ResponseCodeEvent, EventVerdict>
|
||||
{
|
||||
public:
|
||||
ResponseCodeEvent(const ResponseCode &res_code) : http_response_code(res_code) {}
|
||||
|
||||
const ResponseCode & getResponseCode() const { return http_response_code; }
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
ar(http_response_code);
|
||||
}
|
||||
|
||||
void print(std::ostream &out_stream) const { out_stream << http_response_code; }
|
||||
|
||||
private:
|
||||
ResponseCode http_response_code;
|
||||
};
|
||||
|
||||
class EndRequestEvent : public Event<EndRequestEvent, EventVerdict>
|
||||
{
|
||||
};
|
||||
|
||||
class EndTransactionEvent : public Event<EndTransactionEvent, EventVerdict>
|
||||
{
|
||||
};
|
||||
|
||||
class WaitTransactionEvent : public Event<WaitTransactionEvent, EventVerdict>
|
||||
{
|
||||
};
|
||||
|
||||
#endif // __HTTP_INSPECTION_EVENTS_H__
|
||||
47
components/include/http_manager.h
Executable file
47
components/include/http_manager.h
Executable file
@@ -0,0 +1,47 @@
|
||||
// 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_MANAGER_H__
|
||||
#define __HTTP_MANAGER_H__
|
||||
|
||||
#include "singleton.h"
|
||||
#include "i_mainloop.h"
|
||||
#include "i_http_manager.h"
|
||||
#include "i_rest_api.h"
|
||||
#include "i_table.h"
|
||||
#include "i_logging.h"
|
||||
#include "component.h"
|
||||
|
||||
class HttpManager
|
||||
:
|
||||
public Component,
|
||||
Singleton::Provide<I_HttpManager>,
|
||||
Singleton::Consume<I_Table>,
|
||||
Singleton::Consume<I_MainLoop>,
|
||||
Singleton::Consume<I_Logging>,
|
||||
Singleton::Consume<I_TimeGet>
|
||||
{
|
||||
public:
|
||||
HttpManager();
|
||||
~HttpManager();
|
||||
|
||||
void preload();
|
||||
|
||||
void init();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> pimpl;
|
||||
};
|
||||
|
||||
#endif // __HTTP_MANAGER_H__
|
||||
37
components/include/http_transaction_common.h
Normal file
37
components/include/http_transaction_common.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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_TRANSACTION_ENUM_H__
|
||||
#define __HTTP_TRANSACTION_ENUM_H__
|
||||
|
||||
namespace HttpTransaction {
|
||||
|
||||
enum class Method { GET, HEAD, POST, DELETE, CONNECT, OPTIONS, TRACE, PATCH, PUT };
|
||||
enum class Dir { REQUEST, RESPONSE };
|
||||
enum class Verdict { ACCEPT, DROP, INJECT, REDIRECT, NONE, DEFAULT };
|
||||
|
||||
enum class StatusCode {
|
||||
OK = 200,
|
||||
CREATED = 201,
|
||||
NO_CONTENT = 204,
|
||||
NOT_MODIFIED = 304,
|
||||
BAD_REQUEST = 400,
|
||||
UNAUTHORIZED = 401,
|
||||
FORBIDDEN = 403,
|
||||
NOT_FOUND = 404,
|
||||
CONFLICT = 409,
|
||||
INTERNAL_SERVER_ERROR = 500
|
||||
};
|
||||
|
||||
}
|
||||
#endif // __HTTP_TRANSACTION_ENUM_H__
|
||||
136
components/include/http_transaction_data.h
Executable file
136
components/include/http_transaction_data.h
Executable file
@@ -0,0 +1,136 @@
|
||||
// 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_TRANSACTION_DATA_H__
|
||||
#define __HTTP_TRANSACTION_DATA_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "connkey.h"
|
||||
#include "buffer.h"
|
||||
#include "enum_range.h"
|
||||
#include "maybe_res.h"
|
||||
#include "http_transaction_common.h"
|
||||
#include "compression_utils.h"
|
||||
|
||||
class HttpTransactionData
|
||||
{
|
||||
public:
|
||||
HttpTransactionData();
|
||||
|
||||
HttpTransactionData (
|
||||
std::string http_proto,
|
||||
std::string method,
|
||||
std::string host_name,
|
||||
IPAddr listening_ip,
|
||||
uint16_t listening_port,
|
||||
std::string uri,
|
||||
IPAddr client_ip,
|
||||
uint16_t client_port
|
||||
);
|
||||
|
||||
// LCOV_EXCL_START - sync functions, can only be tested once the sync module exists
|
||||
template <class Archive>
|
||||
void
|
||||
save(Archive &ar) const
|
||||
{
|
||||
ar(
|
||||
http_proto,
|
||||
method,
|
||||
host_name,
|
||||
listening_ip,
|
||||
listening_port,
|
||||
uri,
|
||||
client_ip,
|
||||
client_port,
|
||||
response_content_encoding
|
||||
);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void
|
||||
load(Archive &ar)
|
||||
{
|
||||
ar(
|
||||
http_proto,
|
||||
method,
|
||||
host_name,
|
||||
listening_ip,
|
||||
listening_port,
|
||||
uri,
|
||||
client_ip,
|
||||
client_port,
|
||||
response_content_encoding
|
||||
);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
static Maybe<HttpTransactionData> createTransactionData(const Buffer &transaction_raw_data);
|
||||
|
||||
const IPAddr & getSourceIP() const { return client_ip; }
|
||||
uint16_t getSourcePort() const { return client_port; }
|
||||
const IPAddr & getListeningIP() const { return listening_ip; }
|
||||
uint16_t getListeningPort() const { return listening_port; }
|
||||
const std::string & getDestinationHost() const { return host_name; }
|
||||
const std::string & getHttpProtocol() const { return http_proto; }
|
||||
const std::string & getURI() const { return uri; }
|
||||
const std::string & getHttpMethod() const { return method; }
|
||||
|
||||
void print(std::ostream &out_stream) const;
|
||||
|
||||
CompressionType getResponseContentEncoding() const { return response_content_encoding; }
|
||||
bool isRequest() const { return is_request; }
|
||||
|
||||
void setDirection(bool _is_request) { is_request = _is_request; }
|
||||
|
||||
void
|
||||
setResponseContentEncoding(const CompressionType _response_content_encoding)
|
||||
{
|
||||
response_content_encoding = _response_content_encoding;
|
||||
}
|
||||
|
||||
static const std::string http_proto_ctx;
|
||||
static const std::string method_ctx;
|
||||
static const std::string host_name_ctx;
|
||||
static const std::string listening_port_ctx;
|
||||
static const std::string listening_ip_ctx;
|
||||
static const std::string uri_ctx;
|
||||
static const std::string uri_path_decoded;
|
||||
static const std::string uri_query_decoded;
|
||||
static const std::string client_ip_ctx;
|
||||
static const std::string client_port_ctx;
|
||||
static const std::string req_headers;
|
||||
static const std::string req_body;
|
||||
static const std::string source_identifier;
|
||||
static const std::string proxy_ip_ctx;
|
||||
|
||||
static const CompressionType default_response_content_encoding;
|
||||
|
||||
private:
|
||||
std::string http_proto;
|
||||
std::string method = "GET";
|
||||
std::string host_name;
|
||||
IPAddr listening_ip;
|
||||
uint16_t listening_port;
|
||||
std::string uri;
|
||||
IPAddr client_ip;
|
||||
uint16_t client_port;
|
||||
bool is_request;
|
||||
CompressionType response_content_encoding;
|
||||
};
|
||||
|
||||
#endif // __HTTP_TRANSACTION_DATA_H__
|
||||
34
components/include/hybrid_mode_telemetry.h
Executable file
34
components/include/hybrid_mode_telemetry.h
Executable file
@@ -0,0 +1,34 @@
|
||||
// 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 __HYBRID_MODE_TELEMETRY_H__
|
||||
#define __HYBRID_MODE_TELEMETRY_H__
|
||||
|
||||
#include "generic_metric.h"
|
||||
|
||||
class HybridModeMetricEvent : public Event<HybridModeMetricEvent>
|
||||
{
|
||||
public:
|
||||
HybridModeMetricEvent() {}
|
||||
};
|
||||
|
||||
class HybridModeMetric : public GenericMetric, public Listener<HybridModeMetricEvent>
|
||||
{
|
||||
public:
|
||||
void upon(const HybridModeMetricEvent &event) override;
|
||||
|
||||
private:
|
||||
MetricCalculations::LastReportedValue<int> wd_process_restart{this, "watchdogProcessStartupEventsSum"};
|
||||
};
|
||||
|
||||
#endif // __HYBRID_MODE_TELEMETRY_H__
|
||||
42
components/include/i_details_resolver.h
Normal file
42
components/include/i_details_resolver.h
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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 __I_DETAILS_RESOLVER_H__
|
||||
#define __I_DETAILS_RESOLVER_H__
|
||||
|
||||
#include "maybe_res.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class I_DetailsResolver
|
||||
{
|
||||
public:
|
||||
virtual Maybe<std::string> getHostname() = 0;
|
||||
virtual Maybe<std::string> getPlatform() = 0;
|
||||
virtual Maybe<std::string> getArch() = 0;
|
||||
virtual std::string getAgentVersion() = 0;
|
||||
virtual bool isKernelVersion3OrHigher() = 0;
|
||||
virtual bool isGwNotVsx() = 0;
|
||||
virtual bool isVersionEqualOrAboveR8110() = 0;
|
||||
virtual bool isReverseProxy() = 0;
|
||||
virtual Maybe<std::tuple<std::string, std::string, std::string>> parseNginxMetadata() = 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;
|
||||
#endif // gaia || smb
|
||||
|
||||
protected:
|
||||
virtual ~I_DetailsResolver() {}
|
||||
};
|
||||
|
||||
#endif // __I_DETAILS_RESOLVER_H__
|
||||
44
components/include/i_downloader.h
Executable file
44
components/include/i_downloader.h
Executable file
@@ -0,0 +1,44 @@
|
||||
// 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 __I_DOWNLOADER_H__
|
||||
#define __I_DOWNLOADER_H__
|
||||
|
||||
#include "i_orchestration_tools.h"
|
||||
#include "i_update_communication.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class I_Downloader
|
||||
{
|
||||
public:
|
||||
virtual Maybe<std::string> downloadFileFromFog(
|
||||
const std::string &checksum,
|
||||
Package::ChecksumTypes,
|
||||
const GetResourceFile &resourse_file
|
||||
) const = 0;
|
||||
|
||||
virtual Maybe<std::map<std::string, std::string>>downloadVirtualFileFromFog(
|
||||
const GetResourceFile &resourse_file,
|
||||
Package::ChecksumTypes checksum_type
|
||||
) const = 0;
|
||||
|
||||
virtual Maybe<std::string> downloadFileFromURL(
|
||||
const std::string &url,
|
||||
const std::string &checksum,
|
||||
Package::ChecksumTypes checksum_type,
|
||||
const std::string &service_name
|
||||
) const = 0;
|
||||
};
|
||||
|
||||
#endif // __I_DOWNLOADER_H__
|
||||
60
components/include/i_external_sdk_server.h
Executable file
60
components/include/i_external_sdk_server.h
Executable file
@@ -0,0 +1,60 @@
|
||||
// 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 __I_EXTERNAL_SDK_SERVER_H__
|
||||
#define __I_EXTERNAL_SDK_SERVER_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "report/report.h"
|
||||
#include "debug.h"
|
||||
|
||||
class I_ExternalSdkServer
|
||||
{
|
||||
public:
|
||||
virtual void
|
||||
sendLog(
|
||||
const std::string &event_name,
|
||||
ReportIS::Audience audience,
|
||||
ReportIS::Severity severity,
|
||||
ReportIS::Priority priority,
|
||||
const std::string &tag,
|
||||
const std::map<std::string, std::string> &additional_fields) = 0;
|
||||
|
||||
virtual void
|
||||
sendDebug(
|
||||
const std::string &file_name,
|
||||
const std::string &function_name,
|
||||
unsigned int line_number,
|
||||
Debug::DebugLevel debug_level,
|
||||
const std::string &trace_id,
|
||||
const std::string &span_id,
|
||||
const std::string &message,
|
||||
const std::map<std::string, std::string> &additional_fields) = 0;
|
||||
|
||||
virtual void
|
||||
sendMetric(
|
||||
const std::string &event_title,
|
||||
const std::string &service_name,
|
||||
ReportIS::AudienceTeam team,
|
||||
ReportIS::IssuingEngine issuing_engine,
|
||||
const std::map<std::string, std::string> &additional_fields) = 0;
|
||||
|
||||
virtual Maybe<std::string> getConfigValue(const std::string &config_path) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~I_ExternalSdkServer() {}
|
||||
};
|
||||
|
||||
#endif // __I_EXTERNAL_SDK_SERVER_H__
|
||||
36
components/include/i_generic_rulebase.h
Executable file
36
components/include/i_generic_rulebase.h
Executable 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 __I_GENERIC_RULEBASE_H__
|
||||
#define __I_GENERIC_RULEBASE_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "generic_rulebase/parameters_config.h"
|
||||
#include "generic_rulebase/zone.h"
|
||||
#include "config.h"
|
||||
|
||||
class I_GenericRulebase
|
||||
{
|
||||
public:
|
||||
virtual Maybe<Zone, Config::Errors> getLocalZone() const = 0;
|
||||
virtual Maybe<Zone, Config::Errors> getOtherZone() const = 0;
|
||||
|
||||
using ParameterKeyValues = std::unordered_map<std::string, std::set<std::string>>;
|
||||
virtual std::set<ParameterBehavior> getBehavior(const ParameterKeyValues &key_value_pairs) const = 0;
|
||||
|
||||
protected:
|
||||
~I_GenericRulebase() {}
|
||||
};
|
||||
|
||||
#endif // __I_GENERIC_RULEBASE_H__
|
||||
37
components/include/i_gradual_deployment.h
Normal file
37
components/include/i_gradual_deployment.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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 __I_GRADUAL_DEPLOYMENT_H__
|
||||
#define __I_GRADUAL_DEPLOYMENT_H__
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "maybe_res.h"
|
||||
#include "c_common/ip_common.h"
|
||||
|
||||
class I_GradualDeployment
|
||||
{
|
||||
public:
|
||||
enum class AttachmentType { NGINX, KERNEL, COUNT };
|
||||
|
||||
virtual Maybe<void> setPolicy(AttachmentType type, const std::vector<std::string> &str_ip_ranges) = 0;
|
||||
virtual std::vector<std::string> getPolicy(AttachmentType type) = 0;
|
||||
virtual std::vector<IPRange> & getParsedPolicy(AttachmentType type) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~I_GradualDeployment() {}
|
||||
};
|
||||
|
||||
#endif // __I_GRADUAL_DEPLOYMENT_H__
|
||||
34
components/include/i_http_manager.h
Executable file
34
components/include/i_http_manager.h
Executable file
@@ -0,0 +1,34 @@
|
||||
// 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 __I_HTTP_MANAGER_H__
|
||||
#define __I_HTTP_MANAGER_H__
|
||||
|
||||
#include "http_inspection_events.h"
|
||||
|
||||
class I_HttpManager
|
||||
{
|
||||
public:
|
||||
virtual FilterVerdict inspect(const HttpTransactionData &event) = 0;
|
||||
virtual FilterVerdict inspect(const HttpHeader &event, bool is_request) = 0;
|
||||
virtual FilterVerdict inspect(const HttpBody &event, bool is_request) = 0;
|
||||
virtual FilterVerdict inspect(const ResponseCode &event) = 0;
|
||||
virtual FilterVerdict inspectEndRequest() = 0;
|
||||
virtual FilterVerdict inspectEndTransaction() = 0;
|
||||
virtual FilterVerdict inspectDelayedVerdict() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~I_HttpManager() {}
|
||||
};
|
||||
|
||||
#endif // __I_HTTP_MANAGER_H__
|
||||
27
components/include/i_k8s_policy_gen.h
Executable file
27
components/include/i_k8s_policy_gen.h
Executable file
@@ -0,0 +1,27 @@
|
||||
// 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 __I_K8S_POLICY_GEN_H__
|
||||
#define __I_K8S_POLICY_GEN_H__
|
||||
|
||||
class I_K8S_Policy_Gen
|
||||
{
|
||||
public:
|
||||
virtual std::string parsePolicy(const std::string &policy_version) = 0;
|
||||
virtual const std::string & getPolicyPath(void) const = 0;
|
||||
|
||||
protected:
|
||||
~I_K8S_Policy_Gen() {}
|
||||
};
|
||||
|
||||
#endif //__I_K8S_POLICY_GEN_H__
|
||||
26
components/include/i_manifest_controller.h
Executable file
26
components/include/i_manifest_controller.h
Executable file
@@ -0,0 +1,26 @@
|
||||
// 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 __I_MANIFEST_CONTROLLER_H__
|
||||
#define __I_MANIFEST_CONTROLLER_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
class I_ManifestController
|
||||
{
|
||||
public:
|
||||
virtual bool updateManifest(const std::string &new_manifest_file) = 0;
|
||||
virtual bool loadAfterSelfUpdate() = 0;
|
||||
};
|
||||
|
||||
#endif // __I_MANIFEST_CONTROLLER_H__
|
||||
87
components/include/i_orchestration_status.h
Executable file
87
components/include/i_orchestration_status.h
Executable file
@@ -0,0 +1,87 @@
|
||||
// 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 __I_ORCHESTRATION_STATUS_H__
|
||||
#define __I_ORCHESTRATION_STATUS_H__
|
||||
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <cereal/archives/json.hpp>
|
||||
|
||||
#include "enum_array.h"
|
||||
|
||||
enum class OrchestrationStatusResult { SUCCESS, FAILED };
|
||||
enum class OrchestrationStatusFieldType { REGISTRATION, MANIFEST, LAST_UPDATE, COUNT };
|
||||
enum class OrchestrationStatusConfigType { MANIFEST, POLICY, SETTINGS, DATA, COUNT };
|
||||
|
||||
class I_OrchestrationStatus
|
||||
{
|
||||
public:
|
||||
virtual void writeStatusToFile() = 0;
|
||||
|
||||
virtual const std::string & getLastUpdateAttempt() const = 0;
|
||||
virtual const std::string & getUpdateStatus() const = 0;
|
||||
virtual const std::string & getUpdateTime() const = 0;
|
||||
virtual const std::string & getLastManifestUpdate() const = 0;
|
||||
virtual const std::string & getPolicyVersion() const = 0;
|
||||
virtual const std::string & getLastPolicyUpdate() const = 0;
|
||||
virtual const std::string & getLastSettingsUpdate() const = 0;
|
||||
virtual const std::string & getUpgradeMode() const = 0;
|
||||
virtual const std::string & getFogAddress() const = 0;
|
||||
virtual const std::string & getRegistrationStatus() const = 0;
|
||||
virtual const std::string & getAgentId() const = 0;
|
||||
virtual const std::string & getProfileId() const = 0;
|
||||
virtual const std::string & getTenantId() const = 0;
|
||||
virtual const std::string & getManifestStatus() const = 0;
|
||||
virtual const std::string & getManifestError() const = 0;
|
||||
virtual const std::map<std::string, std::string> & getServicePolicies() const = 0;
|
||||
virtual const std::map<std::string, std::string> & getServiceSettings() const = 0;
|
||||
virtual const std::string getRegistrationDetails() const = 0;
|
||||
virtual void recoverFields() = 0;
|
||||
virtual void setIsConfigurationUpdated(EnumArray<OrchestrationStatusConfigType, bool> config_types) = 0;
|
||||
virtual void setFogAddress(const std::string &_fog_address) = 0;
|
||||
virtual void setLastUpdateAttempt() = 0;
|
||||
virtual void setPolicyVersion(const std::string &_policy_version) = 0;
|
||||
virtual void setRegistrationStatus(const std::string &_reg_status) = 0;
|
||||
virtual void setUpgradeMode(const std::string &_upgrade_mode) = 0;
|
||||
virtual void setAgentType(const std::string &_agent_type) = 0;
|
||||
virtual void setAgentDetails(
|
||||
const std::string &_agent_id,
|
||||
const std::string &_profile_id,
|
||||
const std::string &_tenant_id
|
||||
) = 0;
|
||||
|
||||
virtual void
|
||||
setFieldStatus(
|
||||
const OrchestrationStatusFieldType &field_type_status,
|
||||
const OrchestrationStatusResult &status,
|
||||
const std::string &failure_reason = ""
|
||||
) = 0;
|
||||
|
||||
virtual void
|
||||
setRegistrationDetails(
|
||||
const std::string &name,
|
||||
const std::string &type,
|
||||
const std::string &platform,
|
||||
const std::string &arch
|
||||
) = 0;
|
||||
|
||||
virtual void
|
||||
setServiceConfiguration(
|
||||
const std::string &service_name,
|
||||
const std::string &path,
|
||||
const OrchestrationStatusConfigType &configuration_file_type
|
||||
) = 0;
|
||||
};
|
||||
|
||||
#endif // __I_ORCHESTRATION_STATUS_H__
|
||||
125
components/include/i_orchestration_tools.h
Executable file
125
components/include/i_orchestration_tools.h
Executable file
@@ -0,0 +1,125 @@
|
||||
// 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 __I_ORCHESTRATION_TOOLS_H__
|
||||
#define __I_ORCHESTRATION_TOOLS_H__
|
||||
|
||||
#include "package.h"
|
||||
#include "debug.h"
|
||||
#include "maybe_res.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
USE_DEBUG_FLAG(D_ORCHESTRATOR);
|
||||
|
||||
class I_OrchestrationTools
|
||||
{
|
||||
public:
|
||||
// Used for the calculation of the manifest and the policy files
|
||||
static const Package::ChecksumTypes SELECTED_CHECKSUM_TYPE = Package::ChecksumTypes::SHA256;
|
||||
static constexpr const char * SELECTED_CHECKSUM_TYPE_STR = "sha256sum";
|
||||
using packageName = std::string;
|
||||
using packageDetails = std::string;
|
||||
|
||||
template<class T>
|
||||
Maybe<T>
|
||||
jsonFileToObject(const std::string &file_path) const
|
||||
{
|
||||
Maybe<std::string> file_data = readFile(file_path);
|
||||
if (file_data.ok()) {
|
||||
return jsonStringToObject<T>(file_data.unpack());
|
||||
}
|
||||
return genError(file_data.getErr());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Maybe<T>
|
||||
jsonStringToObject(const std::string &input) const
|
||||
{
|
||||
std::stringstream string_stream;
|
||||
string_stream << input;
|
||||
return jsonStringToObject<T>(string_stream);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Maybe<T>
|
||||
jsonStringToObject(std::stringstream &string_stream) const
|
||||
{
|
||||
try {
|
||||
cereal::JSONInputArchive archive_in(string_stream);
|
||||
T object;
|
||||
object.serialize(archive_in);
|
||||
return object;
|
||||
} catch (cereal::Exception &e) {
|
||||
return genError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
objectToJsonFile(T &obj, const std::string &file_path) const
|
||||
{
|
||||
try {
|
||||
std::ofstream ostream(file_path);
|
||||
cereal::JSONOutputArchive archive_out(ostream);
|
||||
obj.serialize(archive_out);
|
||||
} catch (cereal::Exception &e) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to write object to JSON file. Object: " << typeid(T).name()
|
||||
<< ", file : "<< file_path << ", error: " << e.what();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Maybe<std::string>
|
||||
objectToJson(const T &obj) const
|
||||
{
|
||||
std::stringstream sstream;
|
||||
try {
|
||||
cereal::JSONOutputArchive archive_out(sstream);
|
||||
obj.serialize(archive_out);
|
||||
} catch (cereal::Exception &e) {
|
||||
std::string error_msg = "Failed to write object to JSON. Object: " + std::string(typeid(T).name())
|
||||
+ ", error: " + e.what();
|
||||
return genError(error_msg);
|
||||
}
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
virtual bool packagesToJsonFile(const std::map<packageName, Package> &packages, const std::string &path) const = 0;
|
||||
virtual Maybe<std::map<packageName, Package>> loadPackagesFromJson(const std::string &path) const = 0;
|
||||
|
||||
virtual Maybe<std::map<packageName, packageDetails>> jsonObjectSplitter(
|
||||
const std::string &json,
|
||||
const std::string &tenant_id = "") const = 0;
|
||||
|
||||
virtual bool isNonEmptyFile(const std::string &path) const = 0;
|
||||
virtual Maybe<std::string> readFile(const std::string &path) const = 0;
|
||||
virtual bool writeFile(const std::string &text, const std::string &path) const = 0;
|
||||
virtual bool removeFile(const std::string &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 bool createDirectory(const std::string &directory_path) const = 0;
|
||||
virtual bool doesDirectoryExist(const std::string &dir_path) const = 0;
|
||||
virtual bool executeCmd(const std::string &cmd) const = 0;
|
||||
|
||||
virtual std::string base64Encode(const std::string &input) const = 0;
|
||||
virtual std::string base64Decode(const std::string &input) const = 0;
|
||||
|
||||
virtual Maybe<std::string> calculateChecksum(
|
||||
Package::ChecksumTypes checksum_type,
|
||||
const std::string &path) const = 0;
|
||||
};
|
||||
|
||||
#endif // __I_ORCHESTRATION_TOOLS_H__
|
||||
47
components/include/i_package_handler.h
Executable file
47
components/include/i_package_handler.h
Executable file
@@ -0,0 +1,47 @@
|
||||
// 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 __I_PACKAGE_HANDLER_H__
|
||||
#define __I_PACKAGE_HANDLER_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
class I_PackageHandler
|
||||
{
|
||||
public:
|
||||
virtual bool shouldInstallPackage(const std::string &package_name, const std::string &install_file_path) const = 0;
|
||||
|
||||
virtual bool installPackage(
|
||||
const std::string &package_name,
|
||||
const std::string &install_file_path,
|
||||
bool restore_mode
|
||||
) const = 0;
|
||||
virtual bool uninstallPackage(
|
||||
const std::string &package_name,
|
||||
const std::string &package_path,
|
||||
const std::string &install_file_path
|
||||
) const = 0;
|
||||
virtual bool preInstallPackage(
|
||||
const std::string &package_name,
|
||||
const std::string &install_file_path
|
||||
) const = 0;
|
||||
virtual bool postInstallPackage(
|
||||
const std::string &package_name,
|
||||
const std::string &install_file_path
|
||||
) const = 0;
|
||||
virtual bool updateSavedPackage(
|
||||
const std::string &package_name,
|
||||
const std::string &install_file_path
|
||||
) const = 0;
|
||||
};
|
||||
#endif // __I_PACKAGE_HANDLER_H__
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user