mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-29 19:24:26 +03:00
First release of open-appsec source code
This commit is contained in:
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);
|
||||
}
|
Reference in New Issue
Block a user