version 0.0.1

This commit is contained in:
2021-10-23 16:53:40 +02:00
parent 24b5baf73b
commit 1c64f34ef4
92 changed files with 39959 additions and 0 deletions

286
source/Attacker/main.cpp Normal file
View File

@@ -0,0 +1,286 @@
#include <chrono>
#include <fstream>
#include <iostream>
#include <signal.h>
#include "Cli.hpp"
#include "ConfigurationManagement/Configurator.hpp"
#include "Initializer.hpp"
#include "PacketDissection/PacketContainer.hpp"
#include "Threads/AttackThread.hpp"
void handle_quit(int signum);
void terminate(AttackThread** thread_arr, uint16_t nb_worker_threads);
bool quit = false;
std::chrono::time_point<std::chrono::system_clock> start, end;
uint64_t nb_pkts_to_dave = 0;
uint64_t nb_pkts_from_dave = 0;
uint64_t nb_atk_pkts = 0;
uint64_t nb_pkts_to_alice = 0;
uint64_t nb_pkts_from_alice = 0;
uint64_t data_volume_to_alice = 0;
uint64_t data_volume_from_alice = 0;
int pkt_type_used = 0;
int main(int argc, char** argv) {
// ===== INITIALIZE ===== //
// Register signal and signal handler
signal(SIGINT, handle_quit);
Configurator::instance()->read_config("../test/config_attacker.json");
Initializer* init = new Initializer();
unsigned int lcore_id;
uint16_t dave_port = 0;
uint16_t alice_port = 1;
uint16_t nb_worker_threads = 0;
struct rte_mempool* mbuf_pool =
init->init_dpdk_attacker(argc, argv, nb_worker_threads);
// create thread objects
AttackThread* thread_arr[nb_worker_threads];
PacketContainerLean* pkt_containers_to_alice[nb_worker_threads];
PacketContainerLean* pkt_containers_to_dave[nb_worker_threads];
for (int i = 0; i < nb_worker_threads; i++) {
pkt_containers_to_alice[i] =
new PacketContainerLean(mbuf_pool, dave_port, alice_port, i, i);
pkt_containers_to_dave[i] =
new PacketContainerLean(mbuf_pool, alice_port, dave_port, i, i);
thread_arr[i] =
new AttackThread(pkt_containers_to_alice[i],
pkt_containers_to_dave[i], nb_worker_threads);
}
// start each thread on an own lcore
lcore_id = rte_lcore_id();
// run every thread except the last one
for (int i = 0; i < nb_worker_threads; ++i) {
lcore_id = rte_get_next_lcore(lcore_id, true, true);
rte_eal_remote_launch(
static_cast<lcore_function_t*>(AttackThread::s_run), thread_arr[i],
lcore_id);
}
std::cout << "\nRunning. [Ctrl+C to quit]\n" << std::endl;
// ===================START CLI ====================//
std::string input = "";
const std::string NAME = "syntflut";
const char* PATH_ATTACKING_FILE = "/home/guru/is_attacking/attacking";
enum State { RUNNING, IDLE };
State state = IDLE;
while (input != "exit") {
std::cout << NAME << "> ";
std::cin >> input;
std::cout << std::endl;
if (input == "start") {
if (state == IDLE) {
for (int i = 0; i < nb_worker_threads; ++i) {
thread_arr[i]->_do_attack = true;
}
// start measuring time running
start = std::chrono::system_clock::now();
// Start GUI
std::ofstream outfile(PATH_ATTACKING_FILE);
outfile.close();
// ===== RUN =====//
state = RUNNING;
} else { // state == RUNNING
std::cout << "Cannot start if program is already running."
<< std::endl;
}
} else if (input == "stop") {
if (state == IDLE) {
std::cout << "Cannot stop if program is not running."
<< std::endl;
} else { // state == RUNNING
// Stop GUI
std::remove(PATH_ATTACKING_FILE);
end = std::chrono::system_clock::now();
nb_pkts_to_dave = 0;
nb_pkts_from_dave = 0;
nb_pkts_to_alice = 0;
nb_pkts_from_alice = 0;
data_volume_to_alice = 0;
data_volume_from_alice = 0;
pkt_type_used = 0;
for (int i = 0; i < nb_worker_threads; ++i) {
// rescue Informations
nb_pkts_to_dave +=
thread_arr[i]->get_total_nb_pkts_to_dave();
nb_pkts_from_dave +=
thread_arr[i]->get_total_nb_pkts_from_dave();
nb_pkts_to_alice +=
thread_arr[i]->get_total_nb_pkts_to_alice();
nb_pkts_from_alice +=
thread_arr[i]->get_total_nb_pkts_from_alice();
data_volume_to_alice +=
thread_arr[i]->get_total_data_volume_to_alice();
data_volume_from_alice +=
thread_arr[i]->get_total_data_volume_from_alice();
pkt_type_used += thread_arr[i]->get_atk_pkt_type();
thread_arr[i]->_do_attack = false;
}
// print attack statistics
std::chrono::duration<double> elapsed_seconds = end - start;
std::cout << "\nduration of attack:\t\t\t\t"
<< elapsed_seconds.count() << " seconds" << std::endl;
int pkt_size = -1;
if (pkt_type_used > 1) { // TCP:tcp + ip + ether
pkt_size = 20 + 20 + 14;
} else { // UDP: udp + ip + ether
pkt_size = 8 + 20 + 14;
}
nb_atk_pkts = nb_pkts_to_dave - nb_pkts_from_alice;
std::cout << "attack packets sent:\t\t\t\t" << nb_atk_pkts
<< std::endl;
std::cout << "data volume sent (without L1 header):\t\t"
<< nb_atk_pkts * pkt_size / 1048576 << " MByte"
<< std::endl;
std::cout << "data volume sent (with L1 header):\t\t"
<< nb_atk_pkts * 84 / 1048576 << " MByte"
<< std::endl;
std::cout << "average attack rate (without L1 header):\t"
<< nb_atk_pkts * pkt_size / elapsed_seconds.count() /
1048576 * 8
<< " Mbps" << std::endl;
std::cout << "average attack rate (with L1 header):\t\t"
<< nb_atk_pkts * 84 / elapsed_seconds.count() /
1048576 * 8
<< " Mbps" << std::endl;
std::cout << "average attack packet rate:\t\t\t"
<< nb_atk_pkts / elapsed_seconds.count() / 1000
<< " Kpps" << std::endl;
std::cout << "\nnumber packets sent from alice:\t\t\t"
<< nb_pkts_from_alice << std::endl;
std::cout << "number packets recieved by alice:\t\t"
<< nb_pkts_to_alice << std::endl;
std::cout << "average data rate sent from alice:\t\t"
<< data_volume_from_alice / elapsed_seconds.count() /
1024 * 8
<< " Kbps" << std::endl;
std::cout << "average data rate recieved by alice:\t\t"
<< data_volume_to_alice / elapsed_seconds.count() /
1024 * 8
<< " Kbps" << std::endl
<< std::endl;
/*
std::cout << "\nstats for testing:" << std::endl;
std::cout << "number packets sent from dave:\t\t\t"
<< nb_pkts_from_dave << std::endl;
std::cout << "number packets recieved by dave:\t\t\t"
<< nb_pkts_to_dave << std::endl;
std::cout << "attack time:\t\t\t\t\t\t\t\t"
<< elapsed_seconds.count() <<"s" << std::endl;
*/
state = IDLE;
}
} else if (input == "exit") {
// Stop GUI
if (state == RUNNING) {
std::remove(PATH_ATTACKING_FILE);
}
} else if (input == "help" || input == "h") {
std::cout << "start\tstart " << NAME << std::endl
<< "stop\tstop " << NAME << std::endl
<< "help, h\tprint commands " << std::endl
<< "exit\texit " << NAME << std::endl
<< std::endl;
} else {
std::cout << "Command unknown. Try 'h' or 'help'." << std::endl;
}
}
// ====================END CLI ====================//
// ===== TERMINATE ===== //
terminate(thread_arr, nb_worker_threads);
// destruct objects on heap
for (int i = 0; i < nb_worker_threads; ++i) {
delete thread_arr[i];
thread_arr[i] = nullptr;
delete pkt_containers_to_dave[i];
pkt_containers_to_dave[i] = nullptr;
delete pkt_containers_to_alice[i];
pkt_containers_to_alice[i] = nullptr;
}
delete init;
init = nullptr;
// cleanup eal
rte_eal_mp_wait_lcore();
rte_eal_cleanup();
// YOU ARE TERMINATED
}
void handle_quit(int signum) {
// do nothing
}
void terminate(AttackThread** thread_arr, uint16_t nb_worker_threads) {
std::cout << "\nterminating..." << std::endl;
for (int i = 0; i < nb_worker_threads - 1; ++i) {
#ifndef SINGLE_ITERATION
thread_arr[i]->quit();
#endif
}
//wait for threads to end
for (int i = 0; i < nb_worker_threads - 1; ++i) {
while (thread_arr[i]->is_running()) {
// wait
}
}
}

107
source/Cli.cpp Normal file
View File

@@ -0,0 +1,107 @@
#include "Cli.hpp"
Cli::Cli() {
add_to_commands_list("help, h", "Help Screen", std::bind(&Cli::print_help, &*this, std::placeholders::_1));
add_to_commands_list("exit", "Exit Program", std::bind(&Cli::exit_program, &*this, std::placeholders::_1));
}
void Cli::add_to_commands_list(std::string names, std::string desc, Func func) {
Command cmd = std::make_tuple(names, desc, func);
_commands.push_back(cmd);
}
//--------------------------------------------------------------------------------------------------
//------------------------------------------- Run --------------------------------------------------
//--------------------------------------------------------------------------------------------------
void Cli::run() {
while(!_exit) { iterate(); }
}
void Cli::iterate() {
// Ask for input
std::cout << "\033[1;36mAegis: \033[0m";
std::string input;
std::cin >> input;
// Get parameters
std::deque<std::string> parameters;
std::string line;
std::getline(std::cin, line);
std::istringstream iss(line);
std::string arg;
while (iss >> arg) {
parameters.push_back(arg);
}
// Call matching function
Func todo = get_function(input);
todo(parameters);
}
Func Cli::get_function(std::string input) {
for (Command cmd : _commands) {
// Split command names from _commands
std::vector<std::string> names;
boost::split(names, std::get<0>(cmd), boost::is_any_of(", "));
// Check if input matches any of the names
for (std::string name : names) {
if (name == input) {
return std::get<2>(cmd);
}
}
}
// Default: Basic help command
Cli cli;
return std::bind(&Cli::default_help, cli, std::placeholders::_1);
}
//--------------------------------------------------------------------------------------------------
//--------------------------------------- Local Methods --------------------------------------------
//--------------------------------------------------------------------------------------------------
void Cli::default_help(Args args) {
print("Try 'help'");
}
void Cli::exit_program(Args args) {
_exit = true;
}
void Cli::print_help(Args args) {
print("Commands:\n");
if (_commands.size() == 0) {
print("Expty.");
return;
}
// determine max length of first elements
int max_size = 0;
for (auto& c : _commands) {
int len = std::get<0>(c).length();
max_size = (len > max_size) ? len : max_size;
}
// print every available command
for (auto& c : _commands) {
int spaces_to_add = max_size - std::get<0>(c).length();
if (spaces_to_add < 0 || spaces_to_add > 50) { throw "Internal fatal error."; }
std::string command_text;
command_text += std::get<0>(c);
for (int i = 0; i < spaces_to_add; i++) { command_text += " "; }
command_text += " " + std::get<1>(c);
print(command_text);
}
}
void Cli::syn(Args args) {
if (!args.empty()) {
print("SYN " + args[0]);
} else {
print("SYN");
}
}

89
source/Configurator.cpp Normal file
View File

@@ -0,0 +1,89 @@
#include "Configurator.hpp"
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
//-------------------------------------------------------------------------------
//------------------------- Constructor/ Destructor -----------------------------
//-------------------------------------------------------------------------------
Configurator::Configurator(){}
Configurator* Configurator::_instance = nullptr;
Configurator* Configurator::instance(){ // Speicherbereinigung
static CGuard g;
if (!_instance){
_instance = new Configurator ();
}
return _instance;
}
Configurator::~Configurator(){}
//-------------------------------------------------------------------------------
//-------------------------------- Read Config ----------------------------------
//-------------------------------------------------------------------------------
void Configurator::read_config(std::string path,
std::string default_path){
// Read Standard Config
std::ifstream config_file(path);
if(config_file.is_open()){
config_file >> _config;
LOG_INFO << "Config loaded Succesfully" << LOG_END;
}
else {
LOG_INFO << "No Config-File found at " + path << LOG_END;
throw std::runtime_error("No Config-File found at " + path);
}
// Read Default Config
std::ifstream default_config_file(default_path);
if(default_config_file.is_open()){
default_config_file >> _default_config;
LOG_INFO << "Default Config loaded Succesfully" << LOG_END;
}
else {
LOG_ERROR << "No Config-File found at default path " + default_path << LOG_END;
throw std::runtime_error("No Config-File found at deafult path " + default_path);
}
}
//-------------------------------------------------------------------------------
//-------------------------------- Get-Methods ----------------------------------
//-------------------------------------------------------------------------------
bool Configurator::entry_exists(const std::string att_name) {
bool in_default_config = _default_config.find(att_name) != _default_config.end();
bool in_standard_config = _config.find(att_name) != _config.end();
return in_default_config || in_standard_config;
}
std::string Configurator::get_config_as_string(const std::string& att_name, bool default_value) {
return Configurator::get_value_from_config<std::string>(att_name, default_value);
}
unsigned int Configurator::get_config_as_unsigned_int(const std::string& att_name, bool default_value) {
return Configurator::get_value_from_config<int>(att_name, default_value);
}
bool Configurator::get_config_as_bool(const std::string& att_name, bool default_value) {
return Configurator::get_value_from_config<bool>(att_name, default_value);
}
float Configurator::get_config_as_float(const std::string& att_name, bool default_value) {
return Configurator::get_value_from_config<float>(att_name, default_value);
}
double Configurator::get_config_as_double(const std::string& att_name, bool default_value) {
return Configurator::get_value_from_config<double>(att_name, default_value);
}
template <typename T>
T Configurator::get_value_from_config(const std::string& att_name, bool default_value) {
bool search_in_default_config = !(_config.find(att_name) != _config.end()) || default_value;
if (!search_in_default_config) { return _config[att_name]; }
return _default_config[att_name];
}
//TODO Mehrdimensionale Attribute suchen

64
source/DebugHelper.cpp Normal file
View File

@@ -0,0 +1,64 @@
#include "DebugHelper.hpp"
void DebugHelper::hex_dump_human_readable (const char *desc, const void *addr, int len) {
int i;
unsigned char buff[17];
unsigned char *pc = (unsigned char*)addr;
// Output description if given.
if (desc != nullptr)
printf ("%s:\n", desc);
if (len == 0) {
printf(" ZERO LENGTH\n");
return;
}
if (len < 0) {
printf(" NEGATIVE LENGTH: %i\n",len);
return;
}
// Process every byte in the data.
for (i = 0; i < len; i++) {
// Multiple of 16 means new line (with line offset).
if ((i % 16) == 0) {
// Just don't print ASCII for the zeroth line.
if (i != 0)
printf (" || %s\n", buff);
// Output the offset.
printf (" %04x ||", i);
}
// Now the hex code for the specific character.
printf (" %02x", pc[i]);
// And store a printable ASCII character for later.
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
buff[i % 16] = '.';
else
buff[i % 16] = pc[i];
buff[(i % 16) + 1] = '\0';
}
// Pad out last line if not exactly 16 characters.
while ((i % 16) != 0) {
printf (" ");
i++;
}
// And print the final ASCII bit.
printf (" || %s\n", buff);
}
void DebugHelper::hex_dump_raw(const void *addr, int len) {
unsigned char* pc = (unsigned char*) addr;
unsigned char res[2 * len + 1];
res[2 * len] = '\0';
for(unsigned int i = 0; i < len; i++) {
printf((char *)res + i * 2, "%02X", pc[i]);
}
printf ("%s\n", res);
}

278
source/Initializer.cpp Normal file
View File

@@ -0,0 +1,278 @@
#include <rte_eal.h>
#include <rte_lcore.h>
#include <stdexcept>
#include "ConfigurationManagement/Configurator.hpp"
#include "Definitions.hpp"
#include "Initializer.hpp"
rte_mempool* Initializer::init_dpdk(int argc, char** argv,
uint16_t& nb_worker_threads) {
uint8_t hash_key[RSS_HASH_KEY_LENGTH] = {
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A, 0x6D, 0x5A,
};
rte_eth_conf port_conf = {
.rxmode = {.mq_mode = ETH_MQ_RX_RSS,
.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
.offloads = DEV_RX_OFFLOAD_CHECKSUM},
.txmode =
{
.offloads =
(DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM |
DEV_TX_OFFLOAD_TCP_CKSUM),
},
.rx_adv_conf = {.rss_conf =
{
.rss_key = hash_key,
.rss_key_len = RSS_HASH_KEY_LENGTH,
.rss_hf =
ETH_RSS_IP | ETH_RSS_TCP | ETH_RSS_UDP,
}},
};
return init_dpdk_template(NUM_NON_WORKER_THREADS, port_conf, argc, argv,
nb_worker_threads);
}
rte_mempool* Initializer::init_dpdk_attacker(int argc, char** argv,
uint16_t& nb_worker_threads) {
rte_eth_conf port_conf = {
.rxmode =
{
.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
},
.txmode =
{
.offloads =
(DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM |
DEV_TX_OFFLOAD_TCP_CKSUM),
},
};
return init_dpdk_template(0, port_conf, argc, argv, nb_worker_threads);
}
rte_mempool* Initializer::init_dpdk_template(uint16_t nb_non_worker_threads,
rte_eth_conf port_conf, int argc,
char** argv,
uint16_t& nb_worker_threads) {
int ret;
unsigned int nb_ports;
uint16_t portid;
struct rte_mempool* mbuf_pool;
// initialize eal
ret = rte_eal_init(argc, argv);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "Cannot init EAL\n");
}
// initialize number of worker threads
init_number_threads(nb_non_worker_threads, nb_worker_threads);
// Check that there is an even number of ports to send/receive on.
nb_ports = rte_eth_dev_count_avail();
if (nb_ports < 2 || (nb_ports & 1)) {
rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
}
// Creates a new mempool in memory to hold the mbufs.
// This argument must be lower or equal to RTE_MEMPOOL_CACHE_MAX_SIZE (=
// 512)
// and n / 1.5. It is advised to choose cache_size to have "n modulo
// cache_size
// == 0". size from basicfwd program in dpdk examples: 250
unsigned cache_size = RTE_MEMPOOL_CACHE_MAX_SIZE;
if (cache_size > NUM_MBUF_POOL_ELEMENTS / 1.5) {
cache_size = unsigned(NUM_MBUF_POOL_ELEMENTS / 1.5);
}
while (NUM_MBUF_POOL_ELEMENTS % cache_size != 0 || cache_size == 0) {
cache_size -= 1;
}
mbuf_pool =
rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUF_POOL_ELEMENTS, cache_size,
0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == nullptr) {
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
}
// Initialize all ports.
try {
RTE_ETH_FOREACH_DEV(portid) {
init_port(port_conf, portid, mbuf_pool, nb_worker_threads);
}
} catch (std::exception& e) {
rte_exit(EXIT_FAILURE, "Cannot init port %" PRIu16 "\n", portid);
}
return mbuf_pool;
}
void Initializer::init_port(rte_eth_conf port_conf, uint16_t port,
struct rte_mempool* mbuf_pool,
uint16_t nb_worker_threads) {
// the "port" is a port_id which is fetched in the main-function by the
// Makro RTE_ETH_FOREACH_DEV The mbuf_pool is needed for queue
// initialization
const uint16_t rx_rings =
nb_worker_threads; // rte_lcore_count() many worker threads with an
// rx queue on each port
const uint16_t tx_rings = rx_rings; // number of rx and tx queues
uint16_t nb_rxd = RX_RING_SIZE; // size of queues
uint16_t nb_txd = TX_RING_SIZE;
int retval; // return value for later procedure calls
uint16_t q; // counting variable used for for loop
struct rte_eth_dev_info
dev_info; // information about NIC, on which pci_slot...
struct rte_eth_txconf txconf; // filled later with default value of NIC
// test if port exists
if (!rte_eth_dev_is_valid_port(port))
throw std::exception();
// fill def_info with data
rte_eth_dev_info_get(port, &dev_info);
// test if queue has offload capacity; if MBUF offload is possible
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
// |= is not allowed operator. negation of DEV_TX_OFFL...
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
// test if checksum offloading is possible
if (((dev_info.tx_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM) ==
DEV_TX_OFFLOAD_TCP_CKSUM) &&
((dev_info.tx_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM) ==
DEV_TX_OFFLOAD_IPV4_CKSUM)) {
std::cout << "ethernet device is checksum offloading capable"
<< std::endl;
} else {
std::cout << "ethernet device is not checksum offloading capable"
<< std::endl;
}
if (((dev_info.tx_queue_offload_capa & DEV_TX_OFFLOAD_IPV4_CKSUM) ==
DEV_TX_OFFLOAD_IPV4_CKSUM) &&
((dev_info.tx_queue_offload_capa & DEV_TX_OFFLOAD_TCP_CKSUM) ==
DEV_TX_OFFLOAD_TCP_CKSUM)) {
std::cout << "queue is checksum offloading capable" << std::endl;
} else {
std::cout << "queue is not checksum offloading capable" << std::endl;
}
// Configure the Ethernet device.
// address NIC; assign queues; 1 queue per port
retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
if (retval != 0)
throw std::exception();
retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
if (retval != 0)
throw std::exception();
// Allocate and set up RX queues per Ethernet port.
for (q = 0; q < rx_rings; q++) {
retval = rte_eth_rx_queue_setup(
port, q, nb_rxd, rte_eth_dev_socket_id(port), NULL, mbuf_pool);
if (retval < 0)
throw std::exception();
}
// initializes tx config for passing it to the queue setup
txconf = dev_info.default_txconf;
txconf.offloads = port_conf.txmode.offloads;
// Allocate and set up 1 TX queue per Ethernet port.
for (q = 0; q < tx_rings; q++) {
retval = rte_eth_tx_queue_setup(port, q, nb_txd,
rte_eth_dev_socket_id(port), &txconf);
if (retval < 0)
throw std::exception();
}
// Start the Ethernet port.
retval = rte_eth_dev_start(port);
if (retval < 0)
throw std::exception();
// Display the port MAC address.
struct rte_ether_addr addr;
rte_eth_macaddr_get(port, &addr);
printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8
" %02" PRIx8 " %02" PRIx8 "\n",
port, addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
// Enable RX in promiscuous mode for the Ethernet device.
// TODO: do we need it
rte_eth_promiscuous_enable(port);
}
void Initializer::init_number_threads(uint16_t nb_non_worker_threads,
uint16_t& nb_worker_threads) {
// calculate default value of worker threads
uint16_t nb_worker_threads_default =
rte_lcore_count() - nb_non_worker_threads;
// check if value exists or if it has to be calculated
if (Configurator::instance()->entry_exists("number_of_worker_threads")) {
std::string nb = Configurator::instance()->get_config_as_string(
"number_of_worker_threads");
uint16_t nb_int = 0;
try { /* value is convertable to an integer */
nb_int = std::stoi(nb);
} catch (
std::exception& e) { /* value is not convertable to an integer */
throw std::runtime_error(
"The given value at key 'number_of_worker_threads' in "
"config.json is not "
"convertable to an integer value. Set "
"number_of_worker_threads "
"either to 'default' or to a value less or equal than " +
std::to_string(nb_worker_threads_default) +
" and bigger than 0.");
}
if (nb_int > nb_worker_threads_default) {
throw std::runtime_error(
"The given value at key 'number_of_worker_threads' in "
"config.json is out of bounds. Set "
"number_of_worker_threads "
"either to 'default' or to a value smaller or equal than " +
std::to_string(nb_worker_threads_default) +
" and bigger than 0.");
} else if (nb_int <= 0) {
throw std::runtime_error(
"The given value at key 'number_of_worker_threads' in "
"config.json is out of bounds. "
"Either "
"set number_of_worker_threads "
"to 'default' or set it to a value less or equal than " +
std::to_string(nb_worker_threads_default) +
" and greater than 0.");
}
nb_worker_threads = nb_int;
LOG_INFO << "Value " << nb_int
<< " for number_of_worker_threads found in config.json. Using "
<< nb_int << " worker threads and " << nb_non_worker_threads
<< " non worker thread." << LOG_END;
} else {
nb_worker_threads = nb_worker_threads_default;
LOG_INFO << "No value for number_of_worker_threads found in "
"config_attacker.json. Using "
<< nb_worker_threads << " worker threads and "
<< nb_non_worker_threads << " non worker thread." << LOG_END;
}
}

View File

@@ -0,0 +1,127 @@
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include "Definitions.hpp"
#include "Threads/DefenseThread.hpp"
// ===== PUBLIC ===== //
DefenseThread::DefenseThread(
MbufContainerReceiving* mbuf_container_from_inside,
MbufContainerReceiving* mbuf_container_from_outside,
MbufContainerTransmitting* mbuf_container_to_inside,
MbufContainerTransmitting* mbuf_container_to_outside)
: Thread()
, _mbuf_container_from_inside(mbuf_container_from_inside)
, _mbuf_container_from_outside(mbuf_container_from_outside)
, _mbuf_container_to_inside(mbuf_container_to_inside)
, _mbuf_container_to_outside(mbuf_container_to_outside)
, _do_treat(false) {
_treatment =
new Treatment(_mbuf_container_to_outside, _mbuf_container_to_inside, 0);
}
int DefenseThread::s_run(void* thread_vptr) {
DefenseThread* thread = static_cast<DefenseThread*>(thread_vptr);
thread->run();
return 0;
}
// ===== PRIVATE ===== //
void DefenseThread::run() {
/*
LOG_INFO << "\nRunning on lcore " << rte_lcore_id() << ". [Ctrl+C to quit]"
<< LOG_END;
*/
// Run until the application is quit or killed.
while (likely(_quit == false)) {
// std::cout << _do_treat << std::endl;
// continue if no packets are received
int mbufs_from_inside = _mbuf_container_from_inside->poll_mbufs();
/* if (mbufs_from_inside != 0) {
BOOST_LOG_TRIVIAL(info)
<< "Number of packets received from inside: "
<< mbufs_from_inside;
} */
bool keep = true;
for (int i = 0; i < mbufs_from_inside; ++i) {
rte_mbuf* mbuf = _mbuf_container_from_inside->get_mbuf_at_index(i);
if (PacketInfoCreator::is_ipv4_tcp(mbuf) == true &&
_do_treat == true) {
PacketInfoIpv4Tcp* pkt_info = new PacketInfoIpv4Tcp(mbuf);
keep = _treatment->treat_packets_to_outside(pkt_info);
if (keep == false) {
// delete PacketInfo
delete pkt_info;
}
} else {
// fwd
// std::cout << _do_treat;
_mbuf_container_to_outside->add_mbuf(mbuf);
}
}
_mbuf_container_to_inside->send_mbufs();
_mbuf_container_to_outside->send_mbufs();
// _mbuf_container_to_inside->send_mbufs();
// _mbuf_container_to_outside->send_mbufs();
// for mbuf in pktsFromOutside
// pktInfoCreator::determinePacketType without creating a pktinfo
// create packetInfo with obtained type
// if tcp: treat
// else: fwd
// destroy pktInfo
// Pakete von innen, auch die selbsterzeugten bevorzugen
// continue if no packets are received
int mbufs_from_outside = _mbuf_container_from_outside->poll_mbufs();
/* if (mbufs_from_outside != 0) {
BOOST_LOG_TRIVIAL(info)
<< "Number of packets received from outside: "
<< mbufs_from_outside;
} */
for (int i = 0; i < mbufs_from_outside; ++i) {
rte_mbuf* mbuf = _mbuf_container_from_outside->get_mbuf_at_index(i);
if (PacketInfoCreator::is_ipv4_tcp(mbuf) == true &&
_do_treat == true) {
PacketInfoIpv4Tcp* pkt_info = new PacketInfoIpv4Tcp(mbuf);
keep = _treatment->treat_packets_to_inside(
static_cast<PacketInfoIpv4Tcp*>(pkt_info));
if (keep == false) {
// delete PacketInfo
delete pkt_info;
}
} else {
// std::cout << _do_treat;
_mbuf_container_to_inside->add_mbuf(mbuf);
}
}
/* if (_mbuf_container_to_inside->get_number_of_mbufs() > 0) {
BOOST_LOG_TRIVIAL(info)
<< "Number of packets sent to inside: "
<< _mbuf_container_to_inside->get_number_of_mbufs();
}
if (_mbuf_container_to_outside->get_number_of_mbufs() > 0) {
BOOST_LOG_TRIVIAL(info)
<< "Number of packets sent to outside: "
<< _mbuf_container_to_outside->get_number_of_mbufs();
} */
_mbuf_container_to_inside->send_mbufs();
_mbuf_container_to_outside->send_mbufs();
}
_running = false;
}

View File

@@ -0,0 +1,55 @@
#include "Threads/StatisticsThread.hpp"
//-------------------------------------------------------------------------
//-------------------------- StatisticsThread -----------------------------
//-------------------------------------------------------------------------
rte_ring* StatisticsThread::_s_queue[16];
int StatisticsThread::s_run(void* thread_vptr) {
StatisticsThread* thread = static_cast<StatisticsThread*>(thread_vptr);
thread->run();
return 0;
}
void StatisticsThread::run() {
// Check for new statistics in each rte_ring
while (_quit != false) {
for (rte_ring* ring : _s_queue) {
// Get stats from queue and update them
Stats* out;
rte_ring_dequeue(ring, (void**)&out);
if (true) { // \TODO test if empty
update_statistics(out);
}
}
}
}
void StatisticsThread::enqueue_statistics(int& id, Stats* new_stats) {
// enqueue statistics
rte_ring* ring = _s_queue[id];
rte_ring_enqueue(ring, new_stats);
}
Stats* StatisticsThread::_s_stats;
void StatisticsThread::update_statistics(Stats* new_stats) {
//_s_stats += new_stats;
}
//-------------------------------------------------------------------------
//-------------------------- Stats ----------------------------------------
//-------------------------------------------------------------------------
Stats* Stats::operator+=(const Stats* new_stats) {
this->attacks += new_stats->attacks;
this->bytes += new_stats->bytes;
this->dropped += new_stats->dropped;
this->packets += new_stats->packets;
this->work_time += new_stats->work_time;
this->syn_level += new_stats->syn_level;
return this;
}

View File

@@ -0,0 +1,5 @@
#include "Threads/Thread.hpp"
Thread::Thread() : _quit(false) {}
void Thread::quit() { _quit = true; }

View File

@@ -0,0 +1,3 @@
message(' executable: capture ')
sources = files('pkt-capture.cpp')
message(' ------------------------------ ')

View File

@@ -0,0 +1,240 @@
/**
* @file pkt-capture.cpp
*
* @brief Capture packets with dpdk
*
**/
#include <inttypes.h>
#include <rte_cycles.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include <stdint.h>
#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
#define BURST_SIZE 32
/**
* @brief set port configuration
*
*/
// "Portconfig", given by DPDK.
// this struct is a data type with which you have to configure the NIC
// first you create the configuration file which later can be applicated to the
// NIC
static const struct rte_eth_conf port_conf_default = {
// TODO: what does this dot mean?
// the structure of this config-struct is given by the DPDK itself
.rxmode =
{
.max_rx_pkt_len = RTE_ETHER_MAX_LEN,
},
};
/**
* @brief init NIC
*
* get the NIC by port identifier and bind it to dpdk with given mempool.
* Setting up TX/RX queues per ethernet port. Then starting the device and
* printing MAC address
*
* @param port set port identifier to use
* @param mbuf_pool set mempool of dpdk to use
* @return 0 or error code
*/
static inline int port_init(uint16_t port, struct rte_mempool* mbuf_pool) {
// the "port" is a port_id which is fetched in the main-function by the
// Makro RTE_ETH_FOREACH_DEV The mbuf_pool is needed for queue
// initialisation
// config
struct rte_eth_conf port_conf = port_conf_default;
// number of rx and tx queues (i guess)
const uint16_t rx_rings = 1, tx_rings = 1;
// size of queues
uint16_t nb_rxd = RX_RING_SIZE;
uint16_t nb_txd = TX_RING_SIZE;
// return value for later procedure calls
int retval;
// counting variable used for for loop
uint16_t q;
// information about NIC, on which pci_slot...
struct rte_eth_dev_info dev_info;
// filled later with default value of NIC
// TODO: research in doku!
struct rte_eth_txconf txconf;
// does port exist?
if (!rte_eth_dev_is_valid_port(port))
return -1;
// fill def_info with data
rte_eth_dev_info_get(port, &dev_info);
// does queue have offload capacity? Is MBUF offload possible (bool)?
if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE)
// |= is not allowed operator. negation of DEV_TX_OFFL...
port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE;
/* Configure the Ethernet device. */
// address NIC; assign queues; 1 queue per port
retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
if (retval != 0)
return retval;
// nb_rxd ist size of queue (i guess)
retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &nb_rxd, &nb_txd);
if (retval != 0)
return retval;
/* Allocate and set up 1 RX queue per Ethernet port. */
// TODO: This may be the key to RSS
for (q = 0; q < rx_rings; q++) {
retval = rte_eth_rx_queue_setup(
port, q, nb_rxd, rte_eth_dev_socket_id(port), NULL, mbuf_pool);
if (retval < 0)
return retval;
}
// initializes tx config for passing it to the queue setup
txconf = dev_info.default_txconf;
txconf.offloads = port_conf.txmode.offloads;
/* Allocate and set up 1 TX queue per Ethernet port. */
for (q = 0; q < tx_rings; q++) {
retval = rte_eth_tx_queue_setup(port, q, nb_txd,
rte_eth_dev_socket_id(port), &txconf);
if (retval < 0)
return retval;
}
/* Start the Ethernet port. */
// see doc
retval = rte_eth_dev_start(port);
if (retval < 0)
return retval;
/* Display the port MAC address. */
struct rte_ether_addr addr;
rte_eth_macaddr_get(port, &addr);
printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8
" %02" PRIx8 " %02" PRIx8 "\n",
port, addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
/* Enable RX in promiscuous mode for the Ethernet device. */
// see doc
// do we need it?
rte_eth_promiscuous_enable(port);
return 0;
}
/**
* @brief reading from input and writing to output
*
* This is the main thread that does the work, reading from an input port and
* writing to an output port.
*/
static __attribute__((noreturn)) void lcore_main(void) {
// noreturn extension to void
// TODO: see doc!
uint16_t port;
/*
* Check that the port is on the same NUMA node as the polling thread
* for best performance.
*/
RTE_ETH_FOREACH_DEV(port) {
// Ignore this, if we dont use NUMA
if (rte_eth_dev_socket_id(port) > 0 &&
rte_eth_dev_socket_id(port) != (int)rte_socket_id())
printf("WARNING, port %u is on remote NUMA node to "
"polling thread.\n\tPerformance will "
"not be optimal.\n",
port);
}
printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n", rte_lcore_id());
/* Run until the application is quit or killed. */
for (;;) {
/*
* Receive packets on a port and forward them on the paired
* port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
*/
RTE_ETH_FOREACH_DEV(port) {
/* Get burst of RX packets, from first port of pair. */
// poll packets
struct rte_mbuf* bufs[BURST_SIZE];
const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE);
if (unlikely(nb_rx == 0))
continue;
/* Send burst of TX packets, to second port of pair. */
const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, bufs, nb_rx);
/* Free any unsent packets. */
if (unlikely(nb_tx < nb_rx)) {
uint16_t buf;
for (buf = nb_tx; buf < nb_rx; buf++)
rte_pktmbuf_free(bufs[buf]);
}
}
}
}
/**
* @brief init and call per lcore
*
* The main function, which does initialization and calls the per-lcore
* functions.
*/
int main(int argc, char* argv[]) {
struct rte_mempool* mbuf_pool;
unsigned nb_ports;
uint16_t portid;
/* Initialize the Environment Abstraction Layer (EAL). */
int ret = rte_eal_init(argc, argv);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
argc -= ret;
argv += ret;
/* Check that there is an even number of ports to send/receive on. */
nb_ports = rte_eth_dev_count_avail();
if (nb_ports < 2 || (nb_ports & 1))
rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n");
/* Creates a new mempool in memory to hold the mbufs. */
mbuf_pool = rte_pktmbuf_pool_create(
"MBUF_POOL", NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0,
RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mbuf_pool == NULL)
rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
/* Initialize all ports. */
RTE_ETH_FOREACH_DEV(portid) {
if (port_init(portid, mbuf_pool) != 0)
rte_exit(EXIT_FAILURE, "Cannot init port %" PRIu16 "\n", portid);
}
if (rte_lcore_count() > 1)
printf("\nWARNING: Too many lcores enabled. Only 1 used.\n");
/* Call lcore_main on the master core only. */
lcore_main();
return 0;
}

187
source/main.cpp Normal file
View File

@@ -0,0 +1,187 @@
#include <signal.h>
#include "ConfigurationManagement/Configurator.hpp"
#include "Initializer.hpp"
#include "PacketDissection/PacketContainer.hpp"
#include "Threads/DefenseThread.hpp"
void handle_quit(int signum);
void terminate(DefenseThread** thread_arr, uint16_t nb_worker_threads);
bool quit = false;
int main(int argc, char** argv) {
// ===== INITIALIZE ===== //
// Register signal and signal handler
signal(SIGINT, handle_quit);
Configurator::instance()->read_config("../config.json");
Initializer* init = new Initializer();
unsigned int lcore_id;
uint16_t inside_port = 1;
uint16_t outside_port = 0;
uint16_t nb_worker_threads = 0;
struct rte_mempool* mbuf_pool =
init->init_dpdk(argc, argv, nb_worker_threads);
// create thread objects
DefenseThread* thread_arr[nb_worker_threads];
MbufContainerReceiving* pkt_containers_from_outside[nb_worker_threads];
MbufContainerReceiving* pkt_containers_from_inside[nb_worker_threads];
MbufContainerTransmitting* pkt_containers_to_inside[nb_worker_threads];
MbufContainerTransmitting* pkt_containers_to_outside[nb_worker_threads];
for (int i = 0; i < nb_worker_threads; i++) {
pkt_containers_from_outside[i] =
new MbufContainerReceiving(mbuf_pool, outside_port, i);
pkt_containers_from_inside[i] =
new MbufContainerReceiving(mbuf_pool, inside_port, i);
pkt_containers_to_inside[i] =
new MbufContainerTransmitting(mbuf_pool, inside_port, i);
pkt_containers_to_outside[i] =
new MbufContainerTransmitting(mbuf_pool, outside_port, i);
thread_arr[i] = new DefenseThread(
pkt_containers_from_inside[i], pkt_containers_from_outside[i],
pkt_containers_to_inside[i], pkt_containers_to_outside[i]);
}
// start each thread on an own lcore
lcore_id = rte_lcore_id();
for (int i = 0; i < nb_worker_threads; ++i) {
lcore_id = rte_get_next_lcore(lcore_id, true, true);
rte_eal_remote_launch(
static_cast<lcore_function_t*>(DefenseThread::s_run), thread_arr[i],
lcore_id);
}
/*
uint64_t hz = rte_get_tsc_hz();
u_int64_t cycles = rte_get_tsc_cycles();
u_int64_t old_cycles = cycles;
while (likely(quit == false)) {
cycles = rte_get_tsc_cycles();
if (cycles - old_cycles > 64 * hz) {
Treatment::s_increment_timestamp();
old_cycles = cycles;
}
}
*/
// ===================START CLI ====================//
std::string input = "";
const std::string NAME = "aegis";
enum State { RUNNING, IDLE };
State state = IDLE;
while (input != "exit") {
std::cout << std::endl;
std::cout << NAME << "> " << std::flush;
std::cin >> input;
std::cout << std::endl;
if (input == "start") {
if (state == IDLE) {
for (int i = 0; i < nb_worker_threads; ++i) {
thread_arr[i]->start_treat();
}
state = RUNNING;
} else { // state == RUNNING
std::cout << "Cannot start if program is already running."
<< std::endl;
}
} else if (input == "stop") {
if (state == IDLE) {
std::cout << "Cannot stop if program is not running."
<< std::endl;
} else { // state == RUNNING
for (int i = 0; i < nb_worker_threads; ++i) {
thread_arr[i]->stop_treat();
}
state = IDLE;
}
} else if (input == "exit") {
// do nothing; while loop stops
} else if (input == "help" || input == "h") {
std::cout << "start\tstart " << NAME << std::endl
<< "stop\tstop " << NAME << std::endl
<< "help, h\tprint commands " << std::endl
<< "exit\texit " << NAME << std::endl
<< std::endl;
} else {
std::cout << "Command unknown. Try 'h' or 'help'." << std::endl;
}
}
// ====================END CLI ====================//
// ===== TERMINATE ===== //
terminate(thread_arr, nb_worker_threads);
// destruct objects on heap
for (int i = 0; i < nb_worker_threads; ++i) {
delete thread_arr[i];
thread_arr[i] = nullptr;
delete pkt_containers_from_inside[i];
pkt_containers_from_inside[i] = nullptr;
delete pkt_containers_from_outside[i];
pkt_containers_from_outside[i] = nullptr;
delete pkt_containers_to_inside[i];
pkt_containers_to_inside[i] = nullptr;
delete pkt_containers_to_inside[i];
pkt_containers_to_inside[i] = nullptr;
}
delete init;
init = nullptr;
// cleanup eal
rte_eal_mp_wait_lcore();
rte_eal_cleanup();
// YOU ARE TERMINATED
}
void handle_quit(int signum) {
// do nothing
// quit = true;
}
//
void terminate(DefenseThread** thread_arr, uint16_t nb_worker_threads) {
std::cout << "\nterminating..." << std::endl;
for (int i = 0; i < nb_worker_threads; ++i) {
thread_arr[i]->quit();
}
//wait for threads to end
for (int i = 0; i < nb_worker_threads - 1; ++i) {
while (thread_arr[i]->is_running()) {
// wait
}
}
}

21
source/meson.build Normal file
View File

@@ -0,0 +1,21 @@
sources = [
'source/main.cpp',
'source/Initializer.cpp',
'source/DebugHelper.cpp',
'source/ConfigurationManagement/Configurator.cpp',
'source/Threads/DefenseThread.cpp',
'source/Cli.cpp',
#'source/Threads/StatisticsThread.cpp',
]
# Attacker
sources_attack = [
'source/Attacker/main.cpp'
]
foreach string : sources
if string != 'source/main.cpp'
sources_attack += [string]
endif
endforeach