First release of open-appsec source code

This commit is contained in:
roybarda
2022-10-26 19:33:19 +03:00
parent 3883109caf
commit a883352f79
1353 changed files with 276290 additions and 1 deletions

View File

@@ -0,0 +1,13 @@
ADD_DEFINITIONS(-Wno-strict-aliasing)
ADD_DEFINITIONS(-Wno-class-memaccess)
ADD_DEFINITIONS(-Wno-maybe-uninitialized)
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${BOOST_ROOT}/lib ${SHMEM_ROOT}/nginx_cache_shmem)
add_library(shm_pkt_queue SHARED shm_pkt_queue.cc)
target_link_libraries(shm_pkt_queue -lrt)
install(TARGETS shm_pkt_queue DESTINATION lib)
add_subdirectory(shm_pkt_queue_ut)

View File

@@ -0,0 +1,210 @@
// 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 "shmpktqueue.h"
#include <iostream>
#include <map>
#include <sstream>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <sys/time.h>
#include "common.h"
static const int queue_size = 200;
const int shm_pkt_queue_bad_alloc = -2;
namespace bip = boost::interprocess;
using char_alloc = bip::allocator<u_char, bip::managed_shared_memory::segment_manager>;
using shared_string = bip::basic_string<u_char, std::char_traits<u_char>, char_alloc>;
class SharedStringWrapper
{
public:
static void setAlloc(bip::managed_shared_memory::segment_manager *_alloc) { alloc = _alloc; }
SharedStringWrapper() : str(alloc) {}
void reserve(size_t size) { str.reserve(size); }
void append(const u_char *data, size_t len) { str.append(data, len); }
size_t size() const { return str.size(); }
shared_string::iterator begin() { return str.begin(); }
shared_string::iterator end() { return str.end(); }
private:
static bip::managed_shared_memory::segment_manager *alloc;
shared_string str;
};
bip::managed_shared_memory::segment_manager *SharedStringWrapper::alloc = nullptr;
using ring_buffer = boost::lockfree::spsc_queue<SharedStringWrapper, boost::lockfree::capacity<queue_size>>;
class Impl
{
public:
int
init_queue(const char *shm_name, const char *queue_name)
{
if(is_queue_initialized) {
return 0;
}
try {
segment = std::make_unique<bip::managed_shared_memory>(bip::open_only, shm_name);
} catch(...){
// Most likely the shared memory wasn't created yet.
return 0;
}
SharedStringWrapper::setAlloc(segment->get_segment_manager());
queue = segment->find_or_construct<ring_buffer>(queue_name)();
if(queue == nullptr) {
return 0;
}
is_queue_initialized = true;
return 1;
}
int
push_to_queue(
const u_char *msg,
uint16_t length,
shmq_msg_mode mode,
shm_pkt_msg_proto l3_proto,
uint16_t l2_length,
uint16_t if_index)
{
if(!is_queue_initialized) return 0;
SharedStringWrapper packet_node;
shm_pkt_queue_msg_hdr msg_hdr;
msg_hdr.mode = mode;
msg_hdr.l3_proto = l3_proto;
msg_hdr.len = length;
msg_hdr.maclen = l2_length;
msg_hdr.if_index = if_index;
packet_node.reserve(sizeof(msg_hdr) + length);
packet_node.append(reinterpret_cast<u_char *>(&msg_hdr), sizeof(msg_hdr));
packet_node.append(msg, length);
return queue->push(packet_node);
}
u_char *
pop_from_queue()
{
if (is_queue_initialized && queue->read_available()) {
u_char *msg = reinterpret_cast<u_char *>(malloc(queue->front().size()));
if (msg) {
std::copy(queue->front().begin(), queue->front().end(), msg);
queue->pop();
return msg;
}
}
return nullptr;
}
int
is_queue_empty()
{
// uninitialized queue is treated as empty
if(is_queue_initialized && queue->read_available()) {
return 0;
}
return 1;
}
void
clear(void)
{
while (!is_queue_empty()) { queue->pop(); }
}
static Impl&
getRef(shm_pkt_queue_stub *id)
{
return map.at(id);
}
static shm_pkt_queue_stub*
getId()
{
++index;
auto ptr = reinterpret_cast<shm_pkt_queue_stub*>(index);
map.insert(std::make_pair(ptr, Impl()));
return ptr;
}
static void
deleteId(shm_pkt_queue_stub *id)
{
map.erase(id);
}
private:
ring_buffer *queue = nullptr;
std::unique_ptr<bip::managed_shared_memory> segment = nullptr;
bool is_queue_initialized = false;
static std::map<shm_pkt_queue_stub*, Impl> map;
static u_int64_t index;
};
std::map<shm_pkt_queue_stub *, Impl> Impl::map;
u_int64_t Impl::index = 0;
shm_pkt_queue_stub*
get_shm_pkt_queue_id()
{
return Impl::getId();
}
int
init_shm_pkt_queue(shm_pkt_queue_stub *id, const char *shm_name, const char *queue_name)
{
return Impl::getRef(id).init_queue(shm_name, queue_name);
}
int
push_to_shm_pkt_queue(
shm_pkt_queue_stub *id,
const unsigned char *msg,
uint16_t length,
shmq_msg_mode type,
shm_pkt_msg_proto l3_proto,
uint16_t l2_length,
uint16_t if_index)
{
return Impl::getRef(id).push_to_queue(msg, length, type, l3_proto, l2_length, if_index);
}
unsigned char*
pop_from_shm_pkt_queue(shm_pkt_queue_stub *id)
{
return Impl::getRef(id).pop_from_queue();
}
int
is_shm_pkt_queue_empty(shm_pkt_queue_stub *id)
{
return Impl::getRef(id).is_queue_empty();
}
void
delete_shm_pkt_queue(shm_pkt_queue_stub *id)
{
return Impl::deleteId(id);
}

View File

@@ -0,0 +1,9 @@
include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CMAKE_SOURCE_DIR}/fdio_plugin/shm_pkt_queue/include)
include_directories(${CMAKE_SOURCE_DIR}/components/include)
add_unit_test(
shm_pkt_queue_ut
"shm_pkt_queue_ut.cc"
"buffers;shm_pkt_queue;${RT_LIBRARY}"
)

View File

@@ -0,0 +1,291 @@
#include "shmpktqueue.h"
#include <string>
#include <sstream>
#include <boost/lockfree/spsc_queue.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include "cptest.h"
#include "maybe_res.h"
namespace bip = boost::interprocess;
static const int queue_size = 200;
using char_alloc = bip::allocator<u_char, bip::managed_shared_memory::segment_manager>;
using shared_string = bip::basic_string<u_char, std::char_traits<u_char>, char_alloc>;
using ring_buffer = boost::lockfree::spsc_queue<shared_string, boost::lockfree::capacity<queue_size>>;
using namespace std;
static const int segment_name_len = 128;
static const char *queue_name="queue";
static const char *packet_string = "aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffffffffff";
static const u_char *packet_data = reinterpret_cast<const u_char *>(packet_string);
static const uint16_t packet_len = 60;
static const uint16_t l2_len = 14;
static const uint16_t packet_ifn = 1;
static const char *short_packet_string = "aaaaaaaaaabbbbbbbbbbcccccccccc";
static const u_char *short_packet_data = reinterpret_cast<const u_char *>(short_packet_string);
static const uint16_t short_packet_len = 30;
static const uint16_t short_l2_len = 10;
static const uint16_t short_packet_ifn = 0;
static Buffer dns_req { cptestParseHex(
"0000: 00 c0 9f 32 41 8c 00 e0 18 b1 0c ad 08 00 45 00 "
"0010: 00 38 00 00 40 00 40 11 65 47 c0 a8 aa 08 c0 a8 "
"0020: aa 14 80 1b 00 35 00 24 85 ed 10 32 01 00 00 01 "
"0030: 00 00 00 00 00 00 06 67 6f 6f 67 6c 65 03 63 6f "
"0040: 6d 00 00 10 00 01 ")
};
static const uint16_t dns_packet_len = 70;
static const uint16_t dns_l2_len = 14;
static const uint16_t dns_packet_ifn = 4000;
using PacketInfo = struct {
shm_pkt_queue_msg_hdr msg_hdr;
std::unique_ptr<char[]> data;
};
class ShmPktQueueTest : public ::testing::Test {
public:
ShmPktQueueTest()
{
time_t cur_time;
time(&cur_time);
snprintf(
shm_segment_name,
segment_name_len,
"%s_%s",
to_string(cur_time).c_str(),
to_string(::getpid()).c_str()
);
segment = make_unique<bip::managed_shared_memory>(bip::create_only, shm_segment_name, 65536);
queue_id = get_shm_pkt_queue_id();
}
~ShmPktQueueTest()
{
delete_shm_pkt_queue(queue_id);
boost::interprocess::shared_memory_object::remove(shm_segment_name);
}
int
push_packet_to_queue(
Buffer buf,
shmq_msg_mode mode,
shm_pkt_msg_proto l3_proto,
u_int16_t l2_len,
u_int16_t if_index)
{
return push_packet_to_queue(buf.data(), buf.size(), mode, l3_proto, l2_len, if_index);
}
int
push_packet_to_queue(
const unsigned char *data,
u_int16_t length,
shmq_msg_mode mode,
shm_pkt_msg_proto l3_proto,
u_int16_t l2_len,
u_int16_t if_index)
{
return push_to_shm_pkt_queue(queue_id, data, length, mode, l3_proto, l2_len, if_index);
}
Maybe<PacketInfo>
pop_packet_via_boost()
{
ring_buffer *queue = segment->find_or_construct<ring_buffer>(queue_name)();
char_alloc char_alloc(segment->get_segment_manager());
shared_string node_content(char_alloc);
PacketInfo packet_pop_by_boost;
if (queue->pop(node_content)) {
auto parsed_node = reinterpret_cast<const shm_pkt_queue_msg_hdr *>(node_content.data());
packet_pop_by_boost.msg_hdr = *parsed_node;
packet_pop_by_boost.data = std::unique_ptr<char[]>{new char[packet_pop_by_boost.msg_hdr.len]};
std::memcpy(packet_pop_by_boost.data.get(), parsed_node->data, packet_pop_by_boost.msg_hdr.len);
return std::move(packet_pop_by_boost);
}
return genError("Queue is empty");
}
Maybe<PacketInfo>
pop_packet_by_c_api()
{
unsigned char *tmp_packet_pop_by_c_api = pop_from_shm_pkt_queue(queue_id);
PacketInfo packet_pop_by_c_api;
if (tmp_packet_pop_by_c_api) {
auto parsed_node = reinterpret_cast<const shm_pkt_queue_msg_hdr *>(tmp_packet_pop_by_c_api);
packet_pop_by_c_api.msg_hdr = *parsed_node;
packet_pop_by_c_api.data = std::unique_ptr<char[]>{new char[packet_pop_by_c_api.msg_hdr.len]};
std::memcpy(packet_pop_by_c_api.data.get(), parsed_node->data, packet_pop_by_c_api.msg_hdr.len);
free(tmp_packet_pop_by_c_api);
return std::move(packet_pop_by_c_api);
}
return genError("Queue is empty");
}
bool
is_queue_empty()
{
return is_shm_pkt_queue_empty(queue_id);
}
int
init_queue()
{
return init_shm_pkt_queue(queue_id, shm_segment_name, queue_name);
}
shm_pkt_queue_stub * getQueueID() { return queue_id; }
char shm_segment_name[segment_name_len];
private:
shm_pkt_queue_stub *queue_id = nullptr;
std::unique_ptr<bip::managed_shared_memory> segment = nullptr;
};
TEST_F(ShmPktQueueTest, check_queue_emptiness)
{
EXPECT_EQ(init_queue(), 1);
EXPECT_TRUE(is_queue_empty());
EXPECT_EQ(
push_packet_to_queue(packet_data, packet_len, shmq_msg_mode_l2, shmq_msg_no_proto, l2_len, packet_ifn),
1
);
EXPECT_FALSE(is_queue_empty());
auto packet_pop_by_boost = pop_packet_via_boost();
EXPECT_TRUE(is_queue_empty());
}
TEST_F(ShmPktQueueTest, check_push_api)
{
EXPECT_EQ(init_queue(), 1);
EXPECT_EQ(
push_packet_to_queue(packet_data, packet_len, shmq_msg_mode_l2, shmq_msg_no_proto, l2_len, packet_ifn),
1
);
auto packet_pop_by_boost = pop_packet_via_boost();
EXPECT_TRUE(packet_pop_by_boost.ok());
EXPECT_EQ(packet_len, packet_pop_by_boost.unpack().msg_hdr.len);
EXPECT_EQ(l2_len, packet_pop_by_boost.unpack().msg_hdr.maclen);
EXPECT_EQ(packet_ifn, packet_pop_by_boost.unpack().msg_hdr.if_index);
EXPECT_EQ(memcmp(packet_data, packet_pop_by_boost.unpack().data.get(), packet_len), 0);
}
TEST_F(ShmPktQueueTest, check_pop_api)
{
EXPECT_EQ(init_queue(), 1);
EXPECT_EQ(
push_packet_to_queue(packet_data, packet_len, shmq_msg_mode_l2, shmq_msg_no_proto, l2_len, packet_ifn),
1
);
auto packet_pop_by_c_api = pop_packet_by_c_api();
EXPECT_TRUE(packet_pop_by_c_api.ok());
EXPECT_EQ(packet_len, packet_pop_by_c_api.unpack().msg_hdr.len);
EXPECT_EQ(l2_len, packet_pop_by_c_api.unpack().msg_hdr.maclen);
EXPECT_EQ(packet_ifn, packet_pop_by_c_api.unpack().msg_hdr.if_index);
EXPECT_EQ(memcmp(packet_data, packet_pop_by_c_api.unpack().data.get(), packet_len), 0);
}
TEST_F(ShmPktQueueTest, check_dns_real_packet)
{
EXPECT_EQ(init_queue(), 1);
EXPECT_EQ(push_packet_to_queue(dns_req, shmq_msg_mode_l2, shmq_msg_no_proto, dns_l2_len, dns_packet_ifn), 1);
auto dns_packet_pop = pop_packet_by_c_api();
EXPECT_TRUE(dns_packet_pop.ok());
EXPECT_EQ(dns_packet_len, dns_packet_pop.unpack().msg_hdr.len);
EXPECT_EQ(dns_l2_len, dns_packet_pop.unpack().msg_hdr.maclen);
EXPECT_EQ(dns_packet_ifn, dns_packet_pop.unpack().msg_hdr.if_index);
EXPECT_EQ(memcmp(dns_req.data(), dns_packet_pop.unpack().data.get(), dns_packet_len), 0);
}
TEST_F(ShmPktQueueTest, multiple_packets)
{
EXPECT_EQ(init_queue(), 1);
auto empty_packet_pop_by_c_api = pop_packet_by_c_api();
EXPECT_FALSE(empty_packet_pop_by_c_api.ok());
EXPECT_EQ(
push_packet_to_queue(packet_data, packet_len, shmq_msg_mode_l2, shmq_msg_no_proto, l2_len, packet_ifn),
1
);
EXPECT_EQ(
push_packet_to_queue(
short_packet_data,
short_packet_len,
shmq_msg_mode_l2,
shmq_msg_no_proto,
short_l2_len, short_packet_ifn
),
1
);
EXPECT_EQ(push_packet_to_queue(dns_req, shmq_msg_mode_l2, shmq_msg_no_proto, dns_l2_len, dns_packet_ifn), 1);
auto first_packet_pop_by_c_api = pop_packet_by_c_api();
EXPECT_TRUE(first_packet_pop_by_c_api.ok());
EXPECT_EQ(packet_len, first_packet_pop_by_c_api.unpack().msg_hdr.len);
EXPECT_EQ(l2_len, first_packet_pop_by_c_api.unpack().msg_hdr.maclen);
EXPECT_EQ(packet_ifn, first_packet_pop_by_c_api.unpack().msg_hdr.if_index);
EXPECT_EQ(memcmp(packet_data, first_packet_pop_by_c_api.unpack().data.get(), packet_len), 0);
auto second_packet_pop_by_c_api = pop_packet_by_c_api();
EXPECT_TRUE(second_packet_pop_by_c_api.ok());
EXPECT_EQ(short_packet_len, second_packet_pop_by_c_api.unpack().msg_hdr.len);
EXPECT_EQ(short_l2_len, second_packet_pop_by_c_api.unpack().msg_hdr.maclen);
EXPECT_EQ(short_packet_ifn, second_packet_pop_by_c_api.unpack().msg_hdr.if_index);
EXPECT_EQ(memcmp(short_packet_data, second_packet_pop_by_c_api.unpack().data.get(), short_packet_len), 0);
auto third_packet_pop_by_c_api = pop_packet_by_c_api();
EXPECT_TRUE(third_packet_pop_by_c_api.ok());
EXPECT_EQ(dns_packet_len, third_packet_pop_by_c_api.unpack().msg_hdr.len);
EXPECT_EQ(dns_l2_len, third_packet_pop_by_c_api.unpack().msg_hdr.maclen);
EXPECT_EQ(dns_packet_ifn, third_packet_pop_by_c_api.unpack().msg_hdr.if_index);
EXPECT_EQ(memcmp(dns_req.data(), third_packet_pop_by_c_api.unpack().data.get(), dns_l2_len), 0);
auto empty_post_packet_pop_by_c_api = pop_packet_by_c_api();
EXPECT_FALSE(empty_post_packet_pop_by_c_api.ok());
}
TEST_F(ShmPktQueueTest, check_double_init)
{
EXPECT_EQ(init_queue(), 1);
EXPECT_EQ(init_queue(), 0);
}
TEST(NotShmPktQueueTest, check_improper_init)
{
shm_pkt_queue_stub *queue_id = get_shm_pkt_queue_id();
EXPECT_EQ(init_shm_pkt_queue(queue_id, "NoSuchShmDevice", queue_name), 0);
EXPECT_EQ(
push_to_shm_pkt_queue(
queue_id,
packet_data,
packet_len,
shmq_msg_mode_l2,
shmq_msg_no_proto,
l2_len,
packet_ifn
),
0
);
EXPECT_EQ(nullptr, pop_from_shm_pkt_queue(queue_id));
EXPECT_EQ(is_shm_pkt_queue_empty(queue_id), 1);
}
TEST(NotShmPktQueueTest, check_init_after_delete)
{
shm_pkt_queue_stub *queue_id = get_shm_pkt_queue_id();
delete_shm_pkt_queue(queue_id);
EXPECT_THROW(init_shm_pkt_queue(queue_id, "NoSuchShmDevice", queue_name), std::out_of_range);
}