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

56
include/Cli.hpp Normal file
View File

@@ -0,0 +1,56 @@
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <sstream>
#include <boost/algorithm/string.hpp>
using Args = std::deque<std::string>;
using Func = std::function<void(Args)>;
using Command = std::tuple<std::string, std::string, Func>;
class Cli{
public:
/**
* @brief Construct a new Cli object and adds "help, h" and "exit" to _commands.
*/
Cli();
/**
* @brief Adds a command to _commands.
*
* Example: add_to_commands_list("h", "Help", std::bind(&Cli::print_help, &cli, std::placeholders::_1));
*
* @param names string, list of names that execute the command
* @param par string, description to be displayed when help command is executed
* @param func function to be executed (for member functions see example above)
*/
void add_to_commands_list(std::string names, std::string desc, Func func);
/**
* @brief Loops the iterate function. Stops when _exit is set to true.
*/
void run();
/**
* @brief Asks user for input and runs matching method from _commands.
*/
void iterate();
bool get_exit() { return _exit; }
Command& get_command(int i) { return _commands[i]; }
// Functions for commands
void default_help(Args args);
void exit_program(Args args);
void print_help(Args args);
void syn(Args args);
private:
bool _exit = false; ///< When set to true the run method will stop.
std::vector<Command> _commands; ///< Set of commands that can be accessed in the cli.
void print(std::string str) { std::cout << " " << str << "\n"; }
Func get_function(std::string input);
};

107
include/Configurator.hpp Normal file
View File

@@ -0,0 +1,107 @@
#pragma once
#include <boost/log/trivial.hpp>
#include "Definitions.hpp"
#include "iostream"
#include <fstream>
#include <json.hpp>
#include <stdexcept>
using json = nlohmann::json;
class Configurator{
public:
/**
* @brief Checks if attribute exists in either the normal or the default config file
*
* @param att_name Name of attribute that is searched for
* @return true when attribute was found
* @return false when attribute wasn't found
*/
bool entry_exists(const std::string att_name);
//-----------------------------------------------------------------------------------
//------------------------------- Get-Methods ---------------------------------------
//-----------------------------------------------------------------------------------
/**
* @brief Get value from config as string object
*
* @param att_name Name of attribute that is searched for
* @param default_value When set to true the method searches in the default config (default: false)
* @return std::string value
*/
std::string get_config_as_string(const std::string& att_name,
bool default_value = false);
/**
* @brief Get value from config as unsigned integer
*
* @param att_name Name of attribute that is searched for
* @param default_value When set to true the method searches in the default config (default: false)
* @return std::string value
*/
unsigned int get_config_as_unsigned_int(const std::string& att_name,
bool default_value = false);
/**
* @brief Get value from config as boolean
*
* @param att_name Name of attribute that is searched for
* @param default_value When set to true the method searches in the default config (default: false)
* @return std::string value
*/
bool get_config_as_bool(const std::string& att_name,
bool default_value = false);
/**
* @brief Get value from config as float
*
* @param att_name Name of attribute that is searched for
* @param default_value When set to true the method searches in the default config (default: false)
* @return std::string value
*/
float get_config_as_float(const std::string& att_name,
bool default_value = false);
/**
* @brief Get value from config as double
*
* @param att_name Name of attribute that is searched for
* @param default_value When set to true the method searches in the default config (default: false)
* @return std::string value
*/
double get_config_as_double(const std::string& att_name,
bool default_value = false);
/**
* @brief Reads config and default config from json files
*
* @param path Path to standard config (which can be modified by the user)
* @param default_path Path to default config (default: "../default_config.json")
*/
void read_config(std::string path,
std::string default_path = "../default_config.json");
/**
* @brief The Configurator is implemented as a singleton. This method returns a poiter to the Configurator object
*
* @return Configurator* poiter to singleton Configurator
*/
static Configurator* instance();
private:
json _config; ///< standard config (can be modified by the user)
json _default_config; ///< default config
template <typename T> T get_value_from_config(const std::string& att_name, bool default_value);
static Configurator* _instance; ///< singleton Configurator
Configurator();
Configurator(const Configurator&);
~Configurator();
class CGuard{
public:
~CGuard(){
if( NULL != Configurator::_instance ){
delete Configurator::_instance;
Configurator::_instance = nullptr;
}
}
};
};

11
include/DebugHelper.hpp Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include <iostream>
class DebugHelper{
public:
static void hex_dump_human_readable (const char *desc, const void *addr, int len);
static void hex_dump_raw(const void *addr, int len);
};

34
include/Definitions.hpp Normal file
View File

@@ -0,0 +1,34 @@
#pragma once
#define RX_RING_SIZE 1024
#define TX_RING_SIZE 1024
// only needed for mempool creation. was replaced.
// NUM_MBUF_POOL_ELEMENTS is used instead
//#define NUM_MBUFS 8191
// Argument "n" in rte_pktmbuf_pool_create
#define NUM_MBUF_POOL_ELEMENTS 32767
#define BURST_SIZE 64
// #define MBUF_ARR_SIZE 2 * BURST_SIZE
#define RSS_HASH_KEY_LENGTH 40
// used in initializer
#define NUM_NON_WORKER_THREADS 1
// used in PacketContainer.
// predefined size of array of mbuf-arrays
#define NUM_MBUF_ARRS 30000
#define TCP_RX_WINDOW 16384
#define LOG_INFO BOOST_LOG_TRIVIAL(info) << "\e[32m"
#define LOG_WARNING BOOST_LOG_TRIVIAL(warning) << "\e[33m "
#define LOG_ERROR BOOST_LOG_TRIVIAL(error) << "\e[31m "
#define LOG_FATAL BOOST_LOG_TRIVIAL(fatal) << "\e[31m "
#define LOG_END "\e[0m"
// ATTACKE
//#define LOG_PKTS_SENT

52
include/Initializer.hpp Normal file
View File

@@ -0,0 +1,52 @@
#pragma once
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <stdint.h>
class Initializer {
public:
/**
* @brief Initializes everything regarding DPDK and configures the ports.
*
* Especially: Initializes the variable nb_worker_threads
*
* @param[in] argc
* @param[in] argv
* @param[out] mbuf_pool
* @param[out] nb_worker_threads
*/
rte_mempool* init_dpdk(int argc, char** argv, uint16_t& nb_worker_threads);
rte_mempool* init_dpdk_attacker(int argc, char** argv,
uint16_t& nb_worker_threads);
private:
/**
* @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
* @param[in] nb_worker_threads number of worker threads
* @return 0 or error code
*/
void init_port(rte_eth_conf port_conf, uint16_t port,
struct rte_mempool* mbuf_pool, uint16_t nb_worker_threads);
/**
* @brief initializes number of threads
*
* @param[out] nb_worker_threads
*/
void init_number_threads(uint16_t nb_non_worker_threads,
uint16_t& nb_worker_threads);
rte_mempool* init_dpdk_template(uint16_t nb_non_worker_threads,
rte_eth_conf port_conf, int argc,
char** argv, uint16_t& nb_worker_threads);
};

View File

@@ -0,0 +1,56 @@
#pragma once
#include <rte_ethdev.h>
#include <rte_mbuf.h>
#include <stdexcept>
#include "Definitions.hpp"
#define ERROR_STR_MBUF_CONTAINER_INDEX_OUT_OF_BOUNDS \
"Index is out of bounds of MbufContainer."
/**
* @brief like the PacketContainer but it only holds mbufs plus some minor
* performance improvements
*
* \todo Has to be documented with more details
*
*/
class MbufContainer {
protected:
uint16_t _nb_mbufs_in_container;
rte_mbuf* _mbuf_arr[BURST_SIZE];
rte_mempool* _mempool;
public:
inline MbufContainer(rte_mempool* mempool)
: _mempool(mempool), _nb_mbufs_in_container(0) {}
/**
* @brief Get the mbuf at index
*
* @param index
* @return rte_mbuf*
*/
inline rte_mbuf* get_mbuf_at_index(int index) {
check_index(index);
return _mbuf_arr[index];
}
/**
* @brief Get the number of mbufs
*
* @return uint16_t
*/
inline uint16_t get_number_of_mbufs() { return _nb_mbufs_in_container; }
inline void check_index(int index) {
if (unlikely(index >= _nb_mbufs_in_container || index < 0)) {
throw std::runtime_error(
ERROR_STR_MBUF_CONTAINER_INDEX_OUT_OF_BOUNDS);
}
}
};

View File

@@ -0,0 +1,36 @@
#pragma once
#include <rte_ethdev.h>
#include <rte_mbuf.h>
#include "Definitions.hpp"
#include "PacketDissection/MbufContainer.hpp"
/**
* @brief for received mbufs. you poll them, read them and finally... forget
* them
*
*/
class MbufContainerReceiving : public MbufContainer {
private:
uint16_t _rx_port;
uint16_t _rx_queue;
public:
inline MbufContainerReceiving(rte_mempool* mempool, uint16_t rx_port,
uint16_t rx_queue)
: MbufContainer(mempool), _rx_port(rx_port), _rx_queue(rx_queue) {}
/**
* @brief poll mbufs
*
* @return uint16_t
*/
inline uint16_t poll_mbufs() {
_nb_mbufs_in_container =
rte_eth_rx_burst(_rx_port, _rx_queue, _mbuf_arr, BURST_SIZE);
return _nb_mbufs_in_container;
}
};

View File

@@ -0,0 +1,75 @@
#pragma once
#include <rte_ethdev.h>
#include <rte_mbuf.h>
#include "PacketDissection/MbufContainer.hpp"
/**
* @brief for transmitted mbufs.
*
*/
class MbufContainerTransmitting : public MbufContainer {
private:
uint16_t _tx_port;
uint16_t _tx_queue;
public:
inline MbufContainerTransmitting(rte_mempool* mempool, uint16_t tx_port,
uint16_t tx_queue)
: MbufContainer(mempool), _tx_port(tx_port), _tx_queue(tx_queue) {}
/**
* @brief add mbuf to container
*
* This method may delete the mbuf given if the container is full
*
* @param mbuf
*/
inline void add_mbuf(rte_mbuf* mbuf) {
if (likely(_nb_mbufs_in_container < BURST_SIZE)) {
_mbuf_arr[_nb_mbufs_in_container] = mbuf;
++_nb_mbufs_in_container;
} else {
rte_pktmbuf_free(mbuf);
}
}
/**
* @brief create new mbuf in the container and return the pointer to it
*
* @return rte_mbuf*:
* - normally:a newly created mbuf is returned
* -if container is full and no mbuf can be added anymore: nullptr
*/
inline rte_mbuf* get_empty_mbuf() {
if (likely(_nb_mbufs_in_container < BURST_SIZE)) {
_mbuf_arr[_nb_mbufs_in_container] = rte_pktmbuf_alloc(_mempool);
return _mbuf_arr[_nb_mbufs_in_container++];
} else {
return nullptr;
}
}
/**
* @brief send every mbuf contained in the container
*
*/
inline void send_mbufs() {
if (likely(_nb_mbufs_in_container > 0)) {
// send mbufs
uint16_t nb_mbufs_sent = rte_eth_tx_burst(
_tx_port, _tx_queue, _mbuf_arr, _nb_mbufs_in_container);
// Free any unsent packets.
if (unlikely(nb_mbufs_sent < _nb_mbufs_in_container)) {
for (int i = nb_mbufs_sent; i < _nb_mbufs_in_container; ++i) {
rte_pktmbuf_free(_mbuf_arr[i]);
}
}
_nb_mbufs_in_container = 0;
}
}
};

View File

@@ -0,0 +1,563 @@
#pragma once
#include <rte_ethdev.h>
#include <rte_mbuf.h>
#include <rte_mempool.h>
#include <boost/log/trivial.hpp>
#include <stdexcept>
#include <stdint.h>
#include "Definitions.hpp"
#include "PacketDissection/PacketInfo.hpp"
#include "PacketDissection/PacketInfoCreator.hpp"
#define ERROR_STR_INDEX_OUT_OF_BOUNDS \
"index is out of bounds of PacketContainer. The highest possible index " \
"can be accessed by get_total_number_of_packets()."
/**
* This class can poll, send and hold packets.
*
* Think of this data type as a list of packets holding the packets themself
* as well as meta information per packet. If you want to access a certain
* packet (e.g. within a for function) you can use the methods provided with
* a packet index.
*
* You can iterate either only over packets that were polled or over
* all packets in the container.
* - Usually if you create a packet you also want to send it and do not
* look at it anymore after the creation. So the only packets to look at are
* those that where being polled. If this is the case it would be more
* efficient to only iterate over polled packets.
* - The latter includes both packets polled and packets you
* created yourselve with one of the corresponding methods. It could be
* helpful in other situations.
*
* The maximum of packets to iterate over is therefore the
* number of polled packets / the total number of packets which both can be
* accessed each with the corresponding getter method. Remember that the
* indices begin at 0 so the last element is at index (nb_packets - 1).
*
* To manipulate a packet / read data from it you have to get the PacketInfo
* object at a cretain index with the corresponding method. Consult the
* PacketInfo documentation for further information.
*
* NOTICE: It is possible that you get nullptr instead of a PacketInfo
* pointer if you get a packet with one of the corresponding methods. Test
* if this is the case (e.g. ptr == nullptr) before going ahead working with
* the PacketInfo object.
*
* If you want to create a new packet do not construct a new PacketInfo
* object. Use the method get_empty_packet instead. This is more efficient.
*
* An object of this class is initialized with the ID of the rx queue and the
* tx queue of the thread that uses the object. Since corresponding [r|t]x
* queues each on one port have the same ID it is only necessary to store the ID
* of one rx queue and one tx queue.
*/
class PacketContainer {
public:
/**
* @brief Construct a new Packet Container object
*
* @param pkt_handler
* @param mbuf_pool
* @param entrance_port
* @param exit_port
* @param rx_queue_number ID of the rx queues
* @param tx_queue_number ID of the tx queues
*/
inline PacketContainer(struct rte_mempool* mbuf_pool,
uint16_t entrance_port, uint16_t exit_port,
uint16_t rx_queue_number, uint16_t tx_queue_number)
: _mempool(mbuf_pool), _entrance_port(entrance_port),
_exit_port(exit_port), _nb_pkts_polled(0), _nb_pkts_total(0),
_nb_pkts_dropped(0), _nb_pkt_arrays(1),
_rx_queue_number(rx_queue_number), _tx_queue_number(tx_queue_number) {
for (int i = 0; i < NUM_MBUF_ARRS; ++i) {
_nb_mbufs_in_mbuf_arr[i] = 0;
for (int j = 0; j < BURST_SIZE; ++j) {
_mbuf_arrs[i][j] = nullptr;
_pkt_info_arrs[i][j] = nullptr;
}
}
}
~PacketContainer() { empty_container(); }
/**
* @brief Poll packets into the container
*
* The operation poll_packets does not guarantee that more than 0 packets
* were polled. If there are no packets on the NIC port, nothing can be
* polled. So you have to be able to check if packets actually were polled.
* This could be important, e.g if you want to skip certain parts of your
* program if no packets were polled. For the sake of efficiency you do not
* do this with a getter that returns the state but with a pass-by-reference
* variable that you pass to the poll_packets operation- After the execution
* of poll_packets this variable holds the number of packets actually
* polled.
*
* Also if you poll packets but did not send the packets currently being in
* the PacketContainer they are going to be overwritten.
*
* @param[out] nb_pkts_polled after execution: holds number of packets
* actually polled.
*/
inline void poll_packets(uint16_t& nb_pkts_polled) {
empty_container();
_nb_pkts_polled = rte_eth_rx_burst(_entrance_port, _rx_queue_number,
_mbuf_arrs[0], BURST_SIZE);
_nb_pkts_total = _nb_pkts_polled;
if (_nb_pkts_polled > 0) {
_nb_pkt_arrays = 1;
_nb_mbufs_in_mbuf_arr[0] = _nb_pkts_polled;
}
extract_header_info();
// return
nb_pkts_polled = _nb_pkts_polled;
}
/**
* @brief Send packets from the container
*
* Sent packets are no longer available after being sent.
* @return total number of packets send
*/
inline uint send_packets() {
uint sum_pkts_send = 0;
if (likely(_nb_pkts_total > 0)) {
if (_nb_pkts_dropped != 0) {
reorder_mbuf_arrays();
}
for (int i = 0; i < _nb_pkt_arrays; ++i) {
uint16_t nb_pkts_to_send = _nb_mbufs_in_mbuf_arr[i];
// send mbufs
uint16_t nb_pkts_sent =
rte_eth_tx_burst(_exit_port, _tx_queue_number,
_mbuf_arrs[i], nb_pkts_to_send);
#ifdef LOG_PKTS_SENT
LOG_INFO << "Number of packets sent: " << nb_pkts_sent
<< " and this should have been sent: "
<< nb_pkts_to_send << LOG_END;
#endif
sum_pkts_send += nb_pkts_sent;
// Free any unsent packets.
if (unlikely(nb_pkts_sent < nb_pkts_to_send)) {
for (int j = nb_pkts_sent; j < nb_pkts_to_send; ++j) {
rte_pktmbuf_free(_mbuf_arrs[i][j]);
}
}
}
}
empty_container();
return sum_pkts_send;
}
/**
* @brief Drop packet.
*
* @param index Index of the packet to drop.
*/
inline void drop_packet(int index) {
if (index >= _nb_pkts_total) {
throw std::runtime_error(ERROR_STR_INDEX_OUT_OF_BOUNDS);
}
int i = -1;
int j = -1;
calculate_array_coordinates_from_index(index, i, j);
PacketInfoCreator::destroy_pkt_info(_pkt_info_arrs[i][j]);
if (unlikely(_mbuf_arrs[i][j] != nullptr)) {
rte_pktmbuf_free(_mbuf_arrs[i][j]);
}
_pkt_info_arrs[i][j] = nullptr;
_mbuf_arrs[i][j] = nullptr;
++_nb_pkts_dropped;
}
/**
* @brief Drop packet.
*
* @param index Index of the packet to drop.
*/
inline void drop_packet(int index, PacketInfoIpv4Tcp* pkt_to_drop) {
if (index >= _nb_pkts_total) {
throw std::runtime_error(ERROR_STR_INDEX_OUT_OF_BOUNDS);
}
int i = -1;
int j = -1;
calculate_array_coordinates_from_index(index, i, j);
delete pkt_to_drop;
if (unlikely(_mbuf_arrs[i][j] != nullptr)) {
rte_pktmbuf_free(_mbuf_arrs[i][j]);
}
_pkt_info_arrs[i][j] = nullptr;
_mbuf_arrs[i][j] = nullptr;
++_nb_pkts_dropped;
}
/**
* @brief Take the packet
*
* Return a PacketInfo object. The corresponding packet will be removed from
* the PacketContainer so it is no longer in there and will not be sent. The
* only reference available to the packet is the returned PacketInfo
* pointer.
*
* Because the packet is removed from the container the responsibility for
* dropping|sending the packet is up to you. Usually you would add this
* packet to a packet container and sen dor drop the packet afterwards.
*
* If you want to just get the pointer to a PacketInfo object that sould
* remain in the container do not use this method.
*
* @param index
* @return PacketInfo*
*/
inline PacketInfo* take_packet(int index) {
if (index >= _nb_pkts_total) {
throw std::runtime_error(ERROR_STR_INDEX_OUT_OF_BOUNDS);
}
int i, j;
calculate_array_coordinates_from_index(index, i, j);
PacketInfo* pkt_info = _pkt_info_arrs[i][j];
_pkt_info_arrs[i][j] = nullptr;
_mbuf_arrs[i][j] = nullptr;
++_nb_pkts_dropped;
++_nb_pkts_dropped;
return pkt_info;
}
/**
* @brief add Packet to Container which already exists but is stored
* somewhere else.
*
* Add Packet to container which already exists but is stored
* somewhere else. All values (payload and metadata) of the passed mbuf will
* be adopted. These are set as
* parameter of the function call.
*
* @param[in] pkt_container packet container pointer to the packet to be
* added
* @return index of the newly added packet
*/
inline int add_packet(PacketInfo* pkt_info) {
int i, j;
calculate_array_coordinates_from_index(_nb_pkts_total, i, j);
_mbuf_arrs[i][j] = pkt_info->get_mbuf();
_pkt_info_arrs[i][j] = pkt_info;
++_nb_pkts_total;
++_nb_mbufs_in_mbuf_arr[i];
if (unlikely(BURST_SIZE * _nb_pkt_arrays < _nb_pkts_total)) {
++_nb_pkt_arrays;
}
return _nb_pkts_total - 1;
}
/**
* @brief Get the PacketInfo object at index
*
* Use this Method to get a packet and work with it (read, write
* information). You do not have to add it to the PacketContainer again. The
* packet is still in the Container you only get the reference.
*
* @param index
* @return PacketInfo*
*/
inline PacketInfo* get_packet_at_index(int index) {
if (index >= _nb_pkts_total) {
throw std::runtime_error(ERROR_STR_INDEX_OUT_OF_BOUNDS);
}
int i, j;
calculate_array_coordinates_from_index(index, i, j);
return _pkt_info_arrs[i][j];
}
/**
* @brief Get new empty packets PacketInfo to specified packet type
*
* This method is to get you a pointer to an empty PacketInfo object of
* specified type. This pointer is diguised as normal PacketInfo. You can
* work with the PacketInfo object as you want then. You have to cast the
* pointer to specified PacketInfo version to use specific IP and L4
* protocol functions. You do not have to add it to the PacketContainer
* again. The packet is still in the Container you only get the reference.
* This packetInfo already has a mbuf.
*
* @param pkt_type specifies type of PacketInfo which should be created
* @return PacketInfo*
*/
inline PacketInfo* get_empty_packet(PacketType pkt_type) {
int i, j;
calculate_array_coordinates_from_index(_nb_pkts_total, i, j);
++_nb_pkts_total;
++_nb_mbufs_in_mbuf_arr[i];
if (unlikely(BURST_SIZE * _nb_pkt_arrays < _nb_pkts_total)) {
++_nb_pkt_arrays;
}
_mbuf_arrs[i][j] = rte_pktmbuf_alloc(_mempool);
_pkt_info_arrs[i][j] =
PacketInfoCreator::create_pkt_info(_mbuf_arrs[i][j], pkt_type);
return _pkt_info_arrs[i][j];
}
/**
* @brief Get new empty packets PacketInfo to a IPv4TCP packet
*
* This method is to get you a pointer to an empty PacketInfoIpv4Tcp object.
* This pointer is diguised as normal PacketInfo. You can work with the
* PacketInfo object as you want then. You have to cast the pointer to
* PacketInfoIpv4Tcp to use specific IPv4 and TCP functions. You do not have
* to add it to the PacketContainer again. The packet is still in the
* Container you only get the reference. This packetInfo already has a mbuf.
*
* @return PacketInfo*
*/
inline PacketInfo* get_empty_packet() { return get_empty_packet(IPv4TCP); }
/**
* @brief Get the number of polled packets
*
* @return uint16_t
*/
inline uint16_t get_number_of_polled_packets() { return _nb_pkts_polled; }
/**
* @brief Get the total number of packets in the container
*
* @return uint16_t
*/
inline uint16_t get_total_number_of_packets() { return _nb_pkts_total; }
/**
* @brief Get the mempool
*
* @return rte_mempool*
*/
inline rte_mempool* get_mempool() { return _mempool; }
#ifdef TEST
uint16_t* get_nb_mbufs_in_mbuf_arr() { return _nb_mbufs_in_mbuf_arr; }
int get_nb_pkts_dropped() { return _nb_pkts_dropped; }
#endif
protected:
struct rte_mempool* _mempool;
uint16_t _rx_queue_number;
uint16_t _tx_queue_number;
/**
* Port ID of the port the packets are to be polled
* from
*/
uint16_t _entrance_port;
/**
* Port ID of the port the packets are to be sent
* to
*/
uint16_t _exit_port;
/**
* Number of packets that where polled. Newly
* created or added packets are not counted.
*/
uint16_t _nb_pkts_polled;
/**
* Total number of mbufs their references are
* stored in _mbuf_arrs. nullptrs in between valid mbuf pointers are
* counted, too.
*/
uint16_t _nb_pkts_total;
/**
* Number of Arrays that are stored in _mbuf_arrs
*/
int _nb_pkt_arrays;
/**
* Total number of Packets dropped; is increased when a packet is removed
* from the container by take_packet or drop_packet
* \todo rename to _nb_pkts_removed
*/
int _nb_pkts_dropped;
/**
* @brief Array of arrays of [rte_mbuf* |
* PacketInfo*]
*
* A 2d-array is used instead of just a 1d-array to
* be able to store multiple arrays with the fixed
* size of BURST_SIZE. This is necessary if new
* packets are created but the first array is full.
* In this case a new array would be used to store
* newly created packets. Otherwise only one
* 1d-Array is used, the 2d-array-array would have
* just one element then.
*
* Each PacketInfo object is assignet to one and
* only one mbuf. PacketInfo at index "i" holds
* information to mbuf at index "i".
*/
/**@{*/
struct rte_mbuf* _mbuf_arrs[NUM_MBUF_ARRS][BURST_SIZE];
PacketInfo* _pkt_info_arrs[NUM_MBUF_ARRS][BURST_SIZE];
/**@}*/
/**
* Number of mbufs in each sub-array of _mbuf_arrs. nullptrs in between
* valid mbuf pointers are counted, too.
*/
uint16_t _nb_mbufs_in_mbuf_arr[NUM_MBUF_ARRS];
#ifdef TEST
public:
#endif
/**
* @brief Reorder the mbuf arrays; meaning remove nullptrs. So no nullptr
* will be given to the send_packets_to_port method of the
* NetworkPacketHandler.
*/
inline void reorder_mbuf_arrays() {
if (likely(_nb_pkts_total > 0)) {
for (int i = 0; i < _nb_pkt_arrays; ++i) {
// go through mbufs, reorder
int len = _nb_mbufs_in_mbuf_arr[i];
int nb_elements_to_skip = 0;
for (int j = 0; j < len; ++j) {
if (_mbuf_arrs[i][j] == nullptr) {
++nb_elements_to_skip;
} else if (nb_elements_to_skip > 0) {
_mbuf_arrs[i][j - nb_elements_to_skip] =
_mbuf_arrs[i][j];
_mbuf_arrs[i][j] = nullptr;
}
}
_nb_mbufs_in_mbuf_arr[i] -= nb_elements_to_skip;
}
}
}
#ifdef TEST
protected:
#endif
/**
* @brief Calculate the "i" and "j" coordinates for
* a 2d array from a 1d integer "index".
*
* @param[in] index
* @param[out] i
* @param[out] j
*/
inline void calculate_array_coordinates_from_index(int index, int& i,
int& j) {
i = (index - (index % BURST_SIZE)) / BURST_SIZE;
j = index % BURST_SIZE;
}
/**
* @brief Does the what
* calculate_array_coordinates_from_index does but
* in the other direction.
*
* Beware: The order of the arguments is important!
*
* @param[in] i first dimesnion index
* @param[in] j second dimension index
* @param[out] index
*/
inline void calculate_index_from_array_coordinates(int i, int j,
int& index) {
index = i * BURST_SIZE + j;
}
/**
* @brief Set the _state of the container to EMPTY
* and assign variables to 0.
*/
inline void empty_container() {
int nb_pkts_remaining = _nb_pkts_total;
for (int i = 0; i < _nb_pkt_arrays; ++i) {
int len = _nb_mbufs_in_mbuf_arr[i];
for (int j = 0; j < len; ++j) {
if (_pkt_info_arrs[i][j] != nullptr) {
PacketInfoCreator::destroy_pkt_info(_pkt_info_arrs[i][j]);
_pkt_info_arrs[i][j] = nullptr;
}
_mbuf_arrs[i][j] = nullptr;
}
_nb_mbufs_in_mbuf_arr[i] = 0;
}
_nb_pkts_polled = 0;
_nb_pkts_total = 0;
_nb_pkts_dropped = 0;
_nb_pkt_arrays = 0;
}
/**
* @brief creates a PacketInfo for every packet
* in PacketContainer and saves them with
* corresponding index in PacketInfo Array
*
*/
inline void extract_header_info() {
for (int i = 0; i < _nb_pkts_polled; ++i) {
_pkt_info_arrs[0][i] =
fill_info(_mbuf_arrs[0][i], _pkt_info_arrs[0][i]);
}
}
/**
* @brief creates PacketInfo for given mbuf
*
* @param[in] mbuf dpdk abstraction of a packet
* for which a PacketInfo should be created
* @param[out] pkt_inf newly created PacketInfo
*/
inline PacketInfo* fill_info(rte_mbuf* mbuf, PacketInfo* pkt_inf) {
pkt_inf = PacketInfoCreator::create_pkt_info(mbuf);
return pkt_inf;
}
};

View File

@@ -0,0 +1,168 @@
#pragma once
#include "PacketDissection/PacketContainer.hpp"
/**
* @brief This class holds the same functions like the PacketContainer except it
* only holds mbufs and no PacketInfo
*
* only send/reorder etc polled packets. Manually created packets are never
* dropped.
*/
class PacketContainerLean : protected PacketContainer {
public:
inline PacketContainerLean(struct rte_mempool* mbuf_pool,
uint16_t entrance_port, uint16_t exit_port,
uint16_t rx_queue_number,
uint16_t tx_queue_number)
: PacketContainer(mbuf_pool, entrance_port, exit_port, rx_queue_number,
tx_queue_number),
_nb_polled_pkts_dropped(0) {}
inline ~PacketContainerLean() { empty_container_lean(); }
inline void poll_mbufs(uint16_t& nb_mbufs_polled) {
empty_container_lean();
_nb_pkts_polled = rte_eth_rx_burst(_entrance_port, _rx_queue_number,
_mbuf_arrs[0], BURST_SIZE);
_nb_pkts_total = _nb_pkts_polled;
if (likely(_nb_pkts_polled > 0)) {
_nb_pkt_arrays = 1;
_nb_mbufs_in_mbuf_arr[0] = _nb_pkts_polled;
}
// return
nb_mbufs_polled = _nb_pkts_polled;
}
inline uint send_mbufs() {
uint sum_mbufs_send = 0;
if (likely(_nb_pkts_total > 0)) {
if (unlikely(_nb_polled_pkts_dropped != 0)) {
reorder_mbuf_arrays();
}
for (int i = 0; i < _nb_pkt_arrays; ++i) {
uint16_t nb_pkts_to_send = _nb_mbufs_in_mbuf_arr[i];
// send mbufs
uint16_t nb_pkts_sent =
rte_eth_tx_burst(_exit_port, _tx_queue_number,
_mbuf_arrs[i], nb_pkts_to_send);
#ifdef LOG_PKTS_SENT
LOG_INFO << "Number of packets sent: " << nb_pkts_sent
<< LOG_END;
#endif
sum_mbufs_send += nb_pkts_sent;
// Free any unsent packets.
if (unlikely(nb_pkts_sent < nb_pkts_to_send)) {
for (int j = nb_pkts_sent; j < nb_pkts_to_send; ++j) {
rte_pktmbuf_free(_mbuf_arrs[i][j]);
}
}
}
}
empty_container_lean();
return sum_mbufs_send;
}
inline void drop_polled_mbuf(int index) {
if (index >= _nb_pkts_polled) {
throw std::runtime_error(
ERROR_STR_INDEX_OUT_OF_BOUNDS
" No... actually it is _nb_pkts_polled that is exceeded");
}
int i = -1;
int j = -1;
calculate_array_coordinates_from_index(index, i, j);
if (unlikely(_mbuf_arrs[i][j] != nullptr)) {
rte_pktmbuf_free(_mbuf_arrs[i][j]);
}
_pkt_info_arrs[i][j] = nullptr;
_mbuf_arrs[i][j] = nullptr;
++_nb_polled_pkts_dropped;
}
inline rte_mbuf* get_empty_mbuf() {
int i, j;
calculate_array_coordinates_from_index(_nb_pkts_total, i, j);
++_nb_pkts_total;
++_nb_mbufs_in_mbuf_arr[i];
if (unlikely(BURST_SIZE * _nb_pkt_arrays < _nb_pkts_total)) {
++_nb_pkt_arrays;
}
_mbuf_arrs[i][j] = rte_pktmbuf_alloc(_mempool);
return _mbuf_arrs[i][j];
}
inline int add_mbuf(rte_mbuf* mbuf) {
int i = -1;
int j = -1;
calculate_array_coordinates_from_index(_nb_pkts_total, i, j);
_mbuf_arrs[i][j] = mbuf;
++_nb_pkts_total;
++_nb_mbufs_in_mbuf_arr[i];
if (unlikely(BURST_SIZE * _nb_pkt_arrays < _nb_pkts_total)) {
++_nb_pkt_arrays;
}
return _nb_pkts_total - 1;
}
inline uint16_t get_number_of_polled_mbufs() { return _nb_pkts_polled; }
inline rte_mbuf* get_mbuf_at_index(int index) {
if (unlikely(index >= _nb_pkts_total)) {
throw std::runtime_error(ERROR_STR_INDEX_OUT_OF_BOUNDS);
}
int i = -1;
int j = -1;
calculate_array_coordinates_from_index(index, i, j);
return _mbuf_arrs[i][j];
}
inline rte_mempool* get_mempool_lean() { return get_mempool(); }
private:
int _nb_polled_pkts_dropped;
inline void empty_container_lean() {
empty_mbuf_arr();
_nb_pkts_polled = 0;
_nb_pkts_total = 0;
_nb_pkts_dropped = 0;
_nb_polled_pkts_dropped = 0;
_nb_pkt_arrays = 0;
}
inline void empty_mbuf_arr() {
for (int i = 0; i < _nb_pkt_arrays; ++i) {
int len = _nb_mbufs_in_mbuf_arr[i];
for (int j = 0; j < len; ++j) {
_mbuf_arrs[i][j] = nullptr;
}
_nb_mbufs_in_mbuf_arr[i] = 0;
}
}
};

View File

@@ -0,0 +1,93 @@
/**
* @file PacketInfo.hpp
* @author Tobias
* @brief class to provide general packet information
* @date 2021-06-08
*
*/
#pragma once
#include <rte_ether.h>
#include <rte_mbuf.h>
enum PacketType {
NONE,
IPv4ICMP,
IPv4TCP,
IPv4UDP,
IPv6ICMP,
IPv6TCP,
IPv6UDP,
IPv4,
IPv6,
ARP
};
class PacketInfo {
public:
inline PacketInfo() : _type(NONE), _mbuf(nullptr), _eth_hdr(nullptr) {}
inline PacketInfo(rte_mbuf* const mbuf, rte_ether_hdr* const eth_hdr)
: _type(NONE), _mbuf(mbuf), _eth_hdr(eth_hdr) {}
inline ~PacketInfo() {
//_mbuf = nullptr;
}
/**
* @brief Get pointer to mbuf
*
* @return rte_mbuf*
*/
inline rte_mbuf* const get_mbuf() { return _mbuf; }
/**
* @brief Get PacketInfos specialised type
*
* @return PacketType
*/
inline PacketType const get_type() { return _type; }
/**
* @brief Get the source MAC-address
*
* @return rte_ether_addr
*/
inline rte_ether_addr get_src_mac() { return _eth_hdr->s_addr; }
/**
* @brief Get the destination MAC-address
*
* @return rte_ether_addr
*/
inline rte_ether_addr get_dst_mac() { return _eth_hdr->d_addr; }
protected:
inline PacketInfo(PacketType const type, rte_mbuf* const mbuf,
rte_ether_hdr* const eth_hdr)
: _type(type), _mbuf(mbuf), _eth_hdr(eth_hdr) {}
inline PacketInfo(PacketType const type, rte_mbuf* const mbuf)
: _type(type), _mbuf(mbuf), _eth_hdr(nullptr) {}
PacketType const _type;
rte_ether_hdr* const _eth_hdr;
inline rte_ether_hdr* const get_eth_hdr() { return _eth_hdr; }
/**
* @brief fill out standart ethernet header
*
* @param dst_mac MAC-address of destination
* @param src_mac MAC-address of claimed source
*/
inline void fill_eth_hdr(const rte_ether_addr& dst_mac,
const rte_ether_addr& src_mac) {
_eth_hdr->d_addr = dst_mac;
_eth_hdr->s_addr = src_mac;
}
private:
rte_mbuf* const _mbuf;
};

View File

@@ -0,0 +1,290 @@
/**
* @file PacketInfoCreator.hpp
* @author Tobias
* @brief
* @date 2021-06-16
*/
#pragma once
#include <rte_ether.h>
#include <boost/log/trivial.hpp>
#include "Definitions.hpp"
#include "PacketDissection/PacketInfo.hpp"
#include "PacketDissection/PacketInfoIpv4.hpp"
#include "PacketDissection/PacketInfoIpv4Icmp.hpp"
#include "PacketDissection/PacketInfoIpv4Tcp.hpp"
#include "PacketDissection/PacketInfoIpv4Udp.hpp"
#define RTE_ETHER_ADDR_LEN 6
#define ETHER_TYPE_IPv4 0x0800
class PacketInfoCreator {
public:
/**
* @brief Create a PacketInfo object for given mbuf
*
* @param mbuf dpdk abstraction for one packet
* @return PacketInfo*
*/
inline static PacketInfo* create_pkt_info(rte_mbuf* mbuf) {
struct rte_ether_hdr* eth_hdr;
eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*);
uint16_t offset = (uint16_t)sizeof(struct rte_ether_hdr);
/// from here on we know the l3 type
if (rte_be_to_cpu_16(eth_hdr->ether_type) == ETHER_TYPE_IPv4) {
struct rte_ipv4_hdr* ip4_hdr;
ip4_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*, offset);
uint8_t protocol_id = ip4_hdr->next_proto_id;
if (protocol_id == 6) { // TCP
// calculate point where TCP-header begins
offset = offset + (ip4_hdr->version_ihl - 64) * 4;
// map TCP-header on memory
struct rte_tcp_hdr* tcp_hdr;
tcp_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr*, offset);
// create PacketInfo
PacketInfoIpv4Tcp* pkt_inf =
new PacketInfoIpv4Tcp(mbuf, eth_hdr, ip4_hdr, tcp_hdr);
return pkt_inf;
} else if (protocol_id == 17) { // UDP
offset = offset + (ip4_hdr->version_ihl - 64) * 4;
struct rte_udp_hdr* udp_hdr;
udp_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_udp_hdr*, offset);
PacketInfoIpv4Udp* pkt_inf =
new PacketInfoIpv4Udp(mbuf, eth_hdr, ip4_hdr, udp_hdr);
return pkt_inf;
} else if (protocol_id == 1) { // ICMP
offset = offset + (ip4_hdr->version_ihl - 64) * 4;
struct rte_icmp_hdr* icmp_hdr;
icmp_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_icmp_hdr*, offset);
PacketInfoIpv4Icmp* pkt_inf =
new PacketInfoIpv4Icmp(mbuf, eth_hdr, ip4_hdr, icmp_hdr);
return pkt_inf;
} else {
printf("packet is neither TCP UDP nor ICMP");
return new PacketInfo(mbuf, eth_hdr);
}
} else if (rte_be_to_cpu_16(eth_hdr->ether_type) == 0x86DD) {
/// \TODO: implement IPv6
return new PacketInfo(mbuf, eth_hdr);
} else if (rte_be_to_cpu_16(eth_hdr->ether_type) == 0x0806) {
/// \TODO: implement ARP
return new PacketInfo(mbuf, eth_hdr);
} else {
return new PacketInfo(mbuf, eth_hdr);
}
}
/**
* @brief Create a PacketInfo object for given packet type
*
* @param mbuf dpdk abstraction for one packet
* @param type specifies Type which PacketInfo should have
* @return PacketInfo*
*/
inline static PacketInfo* create_pkt_info(rte_mbuf* mbuf, PacketType type) {
int off_set = sizeof(struct rte_ether_hdr);
struct rte_ether_hdr* eth_hdr;
rte_pktmbuf_append(mbuf, sizeof(struct rte_ether_hdr));
eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*);
switch (type) {
case IPv4ICMP: {
eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
struct rte_ipv4_hdr* ip4_hdr;
rte_pktmbuf_append(mbuf, sizeof(rte_ipv4_hdr));
ip4_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*, off_set);
off_set = off_set + sizeof(rte_ipv4_hdr);
rte_pktmbuf_append(mbuf, sizeof(rte_icmp_hdr));
rte_icmp_hdr* icmp_hdr;
icmp_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_icmp_hdr*, off_set);
return new PacketInfoIpv4Icmp(mbuf, eth_hdr, ip4_hdr, icmp_hdr);
} break;
case IPv4TCP: {
eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); // 0x0008
struct rte_ipv4_hdr* ip4_hdr;
rte_pktmbuf_append(mbuf,
sizeof(rte_ipv4_hdr) + sizeof(rte_tcp_hdr));
ip4_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*, off_set);
off_set = off_set + sizeof(rte_ipv4_hdr);
rte_tcp_hdr* tcp_hdr;
tcp_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr*, off_set);
return new PacketInfoIpv4Tcp(mbuf, eth_hdr, ip4_hdr, tcp_hdr);
} break;
case IPv4UDP: {
eth_hdr->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
struct rte_ipv4_hdr* ip4_hdr;
rte_pktmbuf_append(mbuf, sizeof(rte_ipv4_hdr));
ip4_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*, off_set);
off_set = off_set + sizeof(rte_ipv4_hdr);
rte_pktmbuf_append(mbuf, sizeof(rte_udp_hdr));
rte_udp_hdr* udp_hdr;
udp_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_udp_hdr*, off_set);
return new PacketInfoIpv4Udp(mbuf, eth_hdr, ip4_hdr, udp_hdr);
} break;
case IPv6ICMP:
return new PacketInfo(mbuf, eth_hdr);
break;
case IPv6TCP:
return new PacketInfo(mbuf, eth_hdr);
break;
case IPv6UDP:
return new PacketInfo(mbuf, eth_hdr);
break;
default:
return new PacketInfo(mbuf, eth_hdr);
break;
}
}
/**
* @brief Create a minimalized PacketInfo
* this Packet is expected to already have a filled ether header
* and is only for IPv4
* @param mbuf dpdk abstraction for one packet
* @param type specifies Type which PacketInfo should have
* @return PacketInfo*
*/
inline static PacketInfo* create_mini_pkt_info(rte_mbuf* mbuf,
PacketType type) {
int off_set = sizeof(struct rte_ether_hdr);
switch (type) {
case IPv4TCP: {
struct rte_ipv4_hdr* ip4_hdr;
ip4_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*, off_set);
off_set = off_set + sizeof(rte_ipv4_hdr);
rte_tcp_hdr* tcp_hdr;
tcp_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_tcp_hdr*, off_set);
return new PacketInfoIpv4Tcp(mbuf, ip4_hdr, tcp_hdr);
} break;
case IPv4UDP: {
struct rte_ipv4_hdr* ip4_hdr;
ip4_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*, off_set);
off_set = off_set + sizeof(rte_ipv4_hdr);
rte_udp_hdr* udp_hdr;
udp_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_udp_hdr*, off_set);
return new PacketInfoIpv4Udp(mbuf, ip4_hdr, udp_hdr);
} break;
default:
return nullptr;
break;
}
}
/**
* @brief returns a packets destiantion ip
* This method takes an mbuf and extract the IPv4 IP-adress.
* In case the packet inside the mbuf is no IPv4 packet, 0 will be returned
* @param mbuf structure to hand packets over
* @return uint32_t packets IP-adress; it's 0, in case of no IPv4
*/
inline static uint32_t get_dst_ip_from_mbuf(rte_mbuf* mbuf) {
rte_ether_hdr* eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*);
if (eth_hdr->ether_type == rte_cpu_to_be_16(ETHER_TYPE_IPv4)) {
int off_set = sizeof(struct rte_ether_hdr);
rte_ipv4_hdr* ip_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*, off_set);
return rte_be_to_cpu_32(ip_hdr->dst_addr);
} else {
return 0;
}
}
inline static void destroy_pkt_info(PacketInfo* info) {
PacketType type = info->get_type();
switch (type) {
case IPv4TCP: {
delete static_cast<PacketInfoIpv4Tcp*>(info);
} break;
case IPv4UDP: {
delete static_cast<PacketInfoIpv4Udp*>(info);
} break;
case NONE: {
delete info;
} break;
case IPv4ICMP: {
delete static_cast<PacketInfoIpv4Icmp*>(info);
} break;
default:
break;
}
}
inline static bool is_ipv4_tcp(rte_mbuf* mbuf) {
struct rte_ether_hdr* eth_hdr;
eth_hdr = rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*);
if (rte_be_to_cpu_16(eth_hdr->ether_type) == ETHER_TYPE_IPv4) {
uint16_t offset = (uint16_t)sizeof(struct rte_ether_hdr);
struct rte_ipv4_hdr* ip4_hdr;
ip4_hdr =
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*, offset);
uint8_t protocol_id = ip4_hdr->next_proto_id;
if (protocol_id == 6) { // TCP
return true;
} else {
return false;
}
} else {
return false;
}
}
};

View File

@@ -0,0 +1,135 @@
/**
* @file PacketInfoIpv4.hpp
* @author Tobias
* @brief class which provides IPv4 header information
*
*/
#pragma once
#include <boost/log/trivial.hpp>
#include <rte_byteorder.h>
#include <rte_ip.h>
#include <rte_mbuf.h>
#include "Definitions.hpp"
#include "PacketDissection/PacketInfo.hpp"
#define IP_HDR_LEN 20
#define VERSION_AND_IP_HDR_LEN 0b01000101
class PacketInfoIpv4 : public PacketInfo {
public:
PacketInfoIpv4();
inline PacketInfoIpv4(rte_mbuf* const mbuf, rte_ether_hdr* const eth_hdr,
rte_ipv4_hdr* const ip_hdr)
: PacketInfo(IPv4, mbuf, eth_hdr), _ip4_hdr(ip_hdr) {}
inline ~PacketInfoIpv4() {
// PacketInfo::~PacketInfo();
}
/**
* @brief Get packets destination IP address
*
* @return uint32_t
*/
inline uint32_t get_dst_ip() {
return rte_be_to_cpu_32(_ip4_hdr->dst_addr);
}
/**
* @brief Get packets source IP address
*
* @return uint32_t
*/
inline uint32_t get_src_ip() {
return rte_be_to_cpu_32(_ip4_hdr->src_addr);
}
/**
* @brief Set packets source IP address
*
* @param ip
*/
inline void set_src_ip(uint32_t ip) {
_ip4_hdr->src_addr = rte_cpu_to_be_32(ip);
}
/**
* @brief Get packets size in byte
*
* @return uint16_t
*/
inline uint16_t get_packet_size() {
return rte_be_to_cpu_16(_ip4_hdr->total_length);
}
/**
* @brief Get the ip header struct
*
* @return rte_ipv4_hdr*
*/
inline rte_ipv4_hdr* const get_ip_hdr() { return _ip4_hdr; }
void set_ip_cksm(uint16_t cksm);
protected:
inline PacketInfoIpv4(PacketType const type, rte_mbuf* const mbuf,
rte_ether_hdr* const eth_hdr,
rte_ipv4_hdr* const ip_hdr)
: PacketInfo(type, mbuf, eth_hdr), _ip4_hdr(ip_hdr) {}
inline PacketInfoIpv4(PacketType const type, rte_mbuf* const mbuf,
rte_ipv4_hdr* const ip_hdr)
: PacketInfo(type, mbuf), _ip4_hdr(ip_hdr) {}
/**
* @brief fills this packets IPv4 header with neseceties
*
* @param src_ip IP from which packet was originally send from
* @param dst_ip IP packet is send to
* @param proto protocol whose header follows after Ip-header
* @param payload_len packets number of bytes without IP-header
*/
inline void fill_ip_hdr(uint32_t src_ip, uint32_t dst_ip, uint8_t proto,
uint16_t payload_len) {
_ip4_hdr->src_addr = rte_cpu_to_be_32(src_ip);
_ip4_hdr->dst_addr = rte_cpu_to_be_32(dst_ip);
_ip4_hdr->version_ihl = VERSION_AND_IP_HDR_LEN;
_ip4_hdr->type_of_service = 0;
_ip4_hdr->total_length = rte_be_to_cpu_16(payload_len + IP_HDR_LEN);
_ip4_hdr->packet_id = 0;
_ip4_hdr->fragment_offset = 0;
_ip4_hdr->time_to_live = 128;
_ip4_hdr->next_proto_id = proto;
_ip4_hdr->hdr_checksum = 0;
}
inline void recalculate_ip_checksum() {
_ip4_hdr->hdr_checksum = rte_ipv4_cksum(_ip4_hdr);
}
/**
* @brief Get IP pseudo header checksum
*
* @return uint16_t IP pseudo header checksum
*/
inline uint16_t get_pseudo_hdr_cksm() {
rte_mbuf* mbuf = get_mbuf();
mbuf->l2_len = sizeof(struct rte_ether_hdr);
mbuf->l3_len = sizeof(struct rte_ipv4_hdr);
return rte_ipv4_phdr_cksum(_ip4_hdr, mbuf->ol_flags);
}
inline uint8_t get_ip_hdr_len() {
uint8_t len = _ip4_hdr->version_ihl & 0b00001111;
len = len * 4;
return len;
}
private:
rte_ipv4_hdr* const _ip4_hdr;
};

View File

@@ -0,0 +1,45 @@
/**
* @file PacketInfoIpv4Icmp.hpp
* @author Tobias
* @brief class to provide packets IPv4 and ICMP header information
* @date 2021-06-08
*
*/
#pragma once
#include <rte_byteorder.h>
#include <rte_icmp.h>
#include "PacketDissection/PacketInfoIpv4.hpp"
class PacketInfoIpv4Icmp : public PacketInfoIpv4 {
public:
inline PacketInfoIpv4Icmp();
inline PacketInfoIpv4Icmp(rte_mbuf* mbuf, rte_ether_hdr* eth_hdr,
rte_ipv4_hdr* ip_hdr, rte_icmp_hdr* l4_hdr)
: PacketInfoIpv4(IPv4ICMP, mbuf, eth_hdr, ip_hdr), _icmp_hdr(l4_hdr) {}
inline ~PacketInfoIpv4Icmp() {
// PacketInfoIpv4::~PacketInfoIpv4();
_icmp_hdr = nullptr;
}
/**
* @brief Get packets payload size in byte
*
* @return uint16_t
*/
inline uint16_t get_payload_size() { return 0; }
private:
rte_icmp_hdr* _icmp_hdr;
/**
* @brief Set the icmp header struct
*
* @param icmp_hdr
*/
inline void set_icmp_hdr(rte_icmp_hdr* icmp_hdr) {
this->_icmp_hdr = icmp_hdr;
}
};

View File

@@ -0,0 +1,231 @@
/**
* @file PacketInfoIpv4Tcp.hpp
* @author Tobias
* @brief class to provide packets IPv4 and TCP header information
* @date 2021-06-08
*
*/
#pragma once
#include <iostream>
#include <rte_byteorder.h>
#include <rte_tcp.h>
#include "DebugHelper.hpp"
#include "Definitions.hpp"
#include "PacketDissection/PacketInfoIpv4.hpp"
#include "PacketDissection/PacketProtTcp.hpp"
class PacketInfoIpv4Tcp : public PacketInfoIpv4 {
public:
inline PacketInfoIpv4Tcp();
inline PacketInfoIpv4Tcp(rte_mbuf* mbuf)
: PacketInfoIpv4(
IPv4TCP, mbuf, rte_pktmbuf_mtod(mbuf, struct rte_ether_hdr*),
rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr*,
(uint16_t)sizeof(struct rte_ether_hdr)))
, _tcp_hdr(rte_pktmbuf_mtod_offset(
mbuf, struct rte_tcp_hdr*,
(sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr)))) {}
inline PacketInfoIpv4Tcp(rte_mbuf* mbuf, rte_ether_hdr* eth_hdr,
rte_ipv4_hdr* ip_hdr, rte_tcp_hdr* l4_hdr)
: PacketInfoIpv4(IPv4TCP, mbuf, eth_hdr, ip_hdr)
, _tcp_hdr(l4_hdr) {}
inline PacketInfoIpv4Tcp(rte_mbuf* mbuf, rte_ipv4_hdr* ip_hdr,
rte_tcp_hdr* l4_hdr)
: PacketInfoIpv4(IPv4TCP, mbuf, ip_hdr)
, _tcp_hdr(l4_hdr) {}
inline ~PacketInfoIpv4Tcp() {
// PacketInfoIpv4::~PacketInfoIpv4();
// _tcp_hdr = nullptr;
}
/**
* @brief Set packets TCP sequence number
*
* @param seq_num
*/
inline void set_seq_num(uint32_t seq_num) {
PacketProtTcp::set_seq_num(_tcp_hdr, seq_num);
}
/**
* @brief Set packets TCP acknowledgment number
*
* @param ack_num
*/
inline void set_ack_num(uint32_t ack_num) {
PacketProtTcp::set_ack_num(_tcp_hdr, ack_num);
}
/**
* @brief Get packets TCP destination port
*
* @return uint16_t
*/
inline uint16_t get_dst_port() {
return PacketProtTcp::get_dst_port(_tcp_hdr);
}
/**
* @brief Get packets TCP source port
*
* @return uint16_t
*/
inline uint16_t get_src_port() {
return PacketProtTcp::get_src_port(_tcp_hdr);
}
/**
* @brief Get packets TCP flags
* MSB is CWR flag, LSB is FIN flag, NS flag not included
* @return uint8_t
*/
inline uint8_t get_flags() {
const char desc[] = "mbuf";
return PacketProtTcp::get_flags(
_tcp_hdr); // these are FIN to CWR flag, but
// i am not shure in which order
}
/**
* @brief Get packets payload size in byte
*
* @return uint16_t
*/
inline uint16_t get_payload_size() {
uint16_t length = get_packet_size();
length = length - get_ip_hdr_len();
length = length - PacketProtTcp::get_tcp_hdr_len(_tcp_hdr);
return length;
}
/**
* @brief Get packets TCP window size
*
* @return uint16_t
*/
inline uint16_t get_window_size() {
return PacketProtTcp::get_window_size(_tcp_hdr);
}
/**
* @brief Get packets TCP sequence number
*
* @return uint32_t
*/
inline uint32_t get_seq_num() {
return PacketProtTcp::get_seq_num(_tcp_hdr);
}
/**
* @brief Get packets TCP acknowledgment number
*
* @return uint32_t
*/
inline uint32_t get_ack_num() {
return PacketProtTcp::get_ack_num(_tcp_hdr);
}
/**
* @brief Get packets TCP SYN flag
*
* @return true if flag is set
* @return false if flag is not set
*/
inline bool get_syn_flag() { return PacketProtTcp::get_syn_flag(_tcp_hdr); }
/**
* @brief Get packets TCP ACK flag
*
* @return true if flag is set
* @return false if flag is not set
*/
inline bool get_ack_flag() { return PacketProtTcp::get_ack_flag(_tcp_hdr); }
/**
* @brief Get packets TCP RST flag
*
* @return true if flag is set
* @return false if flag is not set
*/
inline bool get_rst_flag() { return PacketProtTcp::get_rst_flag(_tcp_hdr); }
/**
* @brief Get packets TCP FIN flag
*
* @return true if flag is set
* @return false if flag is not set
*/
inline bool get_fin_flag() { return PacketProtTcp::get_fin_flag(_tcp_hdr); }
/**
* @brief fills empty mbuf with IP and TCP header
* If this PacketInfo has a _mbuf and this _mbuf is empty,
* then all IP and TCP header information is filled in.
* This function doesn't create a new mbuf.
* @param src_mac MAC address packet was send from
* @param dst_mac MAC address packet is going to be send to
* @param src_ip IP address packet originally originated from
* @param dst_ip IP address packet is going to be send to
* @param src_port TCP port packet originally was send from
* @param dst_port TCP port packet should be recieved on
* @param seq_num TCP sequence number
* @param ack_num TCP acknowledgment number
* @param flags TCP flags wich are going to be set, can't set NS flag
* @param tcp_window TCP recive window size
*/
inline void fill_payloadless_tcp_packet(
rte_ether_addr src_mac, rte_ether_addr dst_mac, uint32_t src_ip,
uint32_t dst_ip, uint16_t src_port, uint16_t dst_port, uint32_t seq_num,
uint32_t ack_num, uint8_t flags, uint16_t tcp_window) {
// const char desc[] = "mbuf";
// let PacketInfo handle ethernet filling
fill_eth_hdr(dst_mac, src_mac);
// let prot objekt handle tcp filling
PacketProtTcp::fill_payloadless_tcp_header(_tcp_hdr, get_mbuf(),
src_port, dst_port, seq_num,
ack_num, flags, tcp_window);
// let PacketInfoIpv4 handle IPv4 filling
fill_ip_hdr(src_ip, dst_ip, 6, 20);
}
/**
* @brief fills in current checksums
* calculates current IPv4 and TCP checksum and changes
* them inside the packet
*/
inline void recalculate_checksums() {
rte_ipv4_hdr* ip4_hdr = get_ip_hdr();
_tcp_hdr->cksum = 0;
ip4_hdr->hdr_checksum = 0;
_tcp_hdr->cksum = rte_ipv4_udptcp_cksum(ip4_hdr, _tcp_hdr);
PacketInfoIpv4::recalculate_ip_checksum();
}
inline void prepare_offloading_checksums() {
rte_mbuf* mbuf = get_mbuf();
mbuf->ol_flags = PKT_TX_IPV4 | PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM;
mbuf->l4_len = sizeof(struct rte_tcp_hdr);
uint16_t cksm = PacketInfoIpv4::get_pseudo_hdr_cksm();
PacketProtTcp::fill_tcp_cksm(_tcp_hdr, cksm);
}
inline void set_tcp_cksm(uint16_t cksm) {
PacketProtTcp::fill_tcp_cksm(_tcp_hdr, cksm);
}
private:
rte_tcp_hdr* _tcp_hdr;
};

View File

@@ -0,0 +1,135 @@
/**
* @file PacketInfoIpv4Udp.hpp
* @author @Tobias
* @brief class to provide packets IPv4 and UDP header information
* @date 2021-06-08
*
*/
#pragma once
#include <rte_byteorder.h>
#include <rte_udp.h>
#include "PacketDissection/PacketInfoIpv4.hpp"
#include "PacketDissection/PacketProtUdp.hpp"
#define UDP_HDR_LEN 8
class PacketInfoIpv4Udp : public PacketInfoIpv4 {
public:
inline PacketInfoIpv4Udp();
inline PacketInfoIpv4Udp(rte_mbuf* const mbuf, rte_ether_hdr* const eth_hdr,
rte_ipv4_hdr* const ip_hdr,
rte_udp_hdr* const l4_hdr)
: PacketInfoIpv4(IPv4UDP, mbuf, eth_hdr, ip_hdr), _udp_hdr(l4_hdr) {}
inline PacketInfoIpv4Udp(rte_mbuf* const mbuf, rte_ipv4_hdr* const ip_hdr,
rte_udp_hdr* const l4_hdr)
: PacketInfoIpv4(IPv4UDP, mbuf, ip_hdr), _udp_hdr(l4_hdr) {}
// inline PacketInfoIpv4Udp::~PacketInfoIpv4Udp() {
// PacketInfoIpv4::~PacketInfoIpv4();
// //_udp_hdr = nullptr;
//}
/**
* @brief Get packets UDP destination port
*
* @return uint16_t
*/
inline uint16_t get_dst_port() {
return PacketProtUdp::get_dst_port(_udp_hdr);
}
/**
* @brief Get packets UDP source port
*
* @return uint16_t
*/
inline uint16_t get_src_port() {
return PacketProtUdp::get_src_port(_udp_hdr);
}
/**
* @brief Get packets payload size in byte
*
* @return uint16_t
*/
inline uint16_t get_payload_size() {
uint16_t len = get_packet_size();
len = len - get_ip_hdr_len();
return len - UDP_HDR_LEN;
}
/**
* @brief fills empty mbuf with IP and UDP heder
* This PacketInfos _mbuf is going to be filled with all
* IP and UDP header information, execpt checksums.
* This function doesn't create a new mbuf.
* @param src_mac MAC address packet was send from
* @param dst_mac MAC address packet is going to be send to
* @param src_ip IP address packet originally was send from
* @param dst_ip IP address packet is going to be send to
* @param src_port TCP port packet originally was send from
* @param dst_port TCP port packet is going to be send to
*/
inline void fill_payloadless_udp_packet(rte_ether_addr src_mac,
rte_ether_addr dst_mac,
uint32_t src_ip, uint32_t dst_ip,
uint16_t src_port,
uint16_t dst_port) {
// let PacketInfo handle ethernet filling
fill_eth_hdr(dst_mac, src_mac);
// let prot objekt handle tcp filling
PacketProtUdp::fill_payloadless_udp_header(_udp_hdr, src_port,
dst_port);
// let PacketInfoIpv4 handle IPv4 filling
fill_ip_hdr(src_ip, dst_ip, 17, 8);
}
/**
* @brief calculate current checksums and fill them in
* Note, udp checksum doesn't have to be set in IPv4.
* @param use_udp_cksm if true the UDP checksum is calculated
*/
inline void recalculate_checksums(bool use_udp_cksm) {
_udp_hdr->dgram_cksum = 0;
if (use_udp_cksm == true) {
rte_ipv4_hdr* ip_hdr = get_ip_hdr();
ip_hdr->hdr_checksum = 0;
_udp_hdr->dgram_cksum = rte_ipv4_udptcp_cksum(ip_hdr, _udp_hdr);
}
PacketInfoIpv4::recalculate_ip_checksum();
}
/**
* @brief prepare mbuf for checksum calculation by hardware
* Note, udp checksum doesn't have to be set in IPv4.
* @param use_udp_cksm if true the UDP checksum will be calculated
*/
inline void prepare_offloading_checksums(bool use_udp_cksm) {
rte_mbuf* mbuf = get_mbuf();
mbuf->ol_flags = PKT_TX_IPV4 | PKT_TX_IP_CKSUM;
mbuf->l4_len = sizeof(struct rte_udp_hdr);
if (use_udp_cksm == true) {
mbuf->ol_flags |= PKT_TX_UDP_CKSUM;
_udp_hdr->dgram_cksum = PacketInfoIpv4::get_pseudo_hdr_cksm();
} else {
mbuf->l2_len = sizeof(struct rte_ether_hdr);
mbuf->l3_len = sizeof(struct rte_ipv4_hdr);
}
}
private:
rte_udp_hdr* const _udp_hdr;
};

View File

@@ -0,0 +1,58 @@
/**
* @file PacketInfoIpv6Icmp.hpp
* @author Tobias
* @brief class to provide packets IPv6 and ICMP header information
* @date 2021-06-09
*
*/
#pragma once
#include <iostream>
#include <rte_byteorder.h>
#include <rte_ether.h>
#include <rte_icmp.h>
#include <rte_ip.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include "PacketDissection/PacketInfo.hpp"
class PacketInfoIpv6Icmp : public PacketInfo {
public:
inline PacketInfoIpv6Icmp() { /*set_type(IPv6ICMP);*/
}
inline void set_ip_hdr(rte_ipv6_hdr* ip6_hdr) { this->_ip6_hdr = ip6_hdr; }
inline void set_icmp_hdr(rte_icmp_hdr* icmp_hdr) {
this->_icmp_hdr = icmp_hdr;
}
/// IPv6 Functions
inline uint32_t get_dst_ip() {
/*__uint128_t dest_ip = 0;
for (short i = 0; i < 16; i++){
dest_ip << 8; /// shift left to make space for next part
dest_ip = dest_ip + _ip6_hdr->dst_addr[i]; /// add next part
}*/
std::cout << "PacketInfoIpv6Icmp not yet implemented! ";
return 0;
}
inline uint32_t get_src_ip() {
/*__uint128_t src_ip = 0;
for (short i = 0; i < 16; i++){
src_ip << 8; /// shift left to make space for next part
src_ip = src_ip + _ip6_hdr->src_addr[i]; /// add next part
}*/
printf("PacketInfoIpv6Icmp not yet implemented! ");
return 0;
}
inline uint16_t get_packet_size() { return 384; }
inline uint16_t get_payload_size() { return 0; }
private:
rte_ipv6_hdr* _ip6_hdr;
rte_icmp_hdr* _icmp_hdr;
};

View File

@@ -0,0 +1,106 @@
/**
* @file PacketInfoIpv6Tcp.hpp
* @author Tobias
* @brief class to provide packets IPv6 and TCP header information
* @date 2021-06-09
*
*/
#pragma once
#include <iostream>
#include <rte_byteorder.h>
#include <rte_ether.h>
#include <rte_icmp.h>
#include <rte_ip.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include <rte_tcp.h>
#include <rte_udp.h>
#include "PacketDissection/PacketInfo.hpp"
class PacketInfoIpv6Tcp : public PacketInfo {
public:
inline PacketInfoIpv6Tcp() { /*set_type(IPv6TCP);*/
}
inline void create_reply(rte_mbuf* answ_mbuf, uint32_t seq_num,
uint32_t ack_num);
inline void tear_down_connection(rte_mbuf* return_mbuf,
rte_mbuf* forward_mbuf,
uint32_t forward_seq_num,
uint32_t forward_ack_num);
inline void set_ip_hdr(rte_ipv6_hdr* ip6_hdr) { this->_ip6_hdr = ip6_hdr; }
inline void set_tcp_hdr(rte_tcp_hdr* tcp_hdr) { this->_tcp_hdr = tcp_hdr; }
inline void set_seq_num(uint32_t seq_num) { _tcp_hdr->sent_seq = seq_num; }
inline void set_ack_num(uint32_t ack_num) { _tcp_hdr->recv_ack = ack_num; }
/// IPv6 Functions
inline uint32_t get_dst_ip() {
/*__uint128_t dest_ip = 0;
for (short i = 0; i < 16; i++){
dest_ip = dest_ip * 256; /// shift left to make space for next
part dest_ip = dest_ip + _ip6_hdr->dst_addr[i]; /// add next part
}*/
std::cout << "PacketInfoIpv6Tcp not yet implemented! ";
return 0;
}
inline uint32_t get_src_ip() {
/*__uint128_t src_ip = 0;
for (short i = 0; i < 16; i++){
src_ip = src_ip * 256; /// shift left to make space for next part
src_ip = src_ip + _ip6_hdr->src_addr[i]; /// add next part
}*/
printf("PacketInfoIpv6Tcp not yet implemented! ");
return 0;
}
inline uint16_t get_dst_port() { return _tcp_hdr->dst_port; }
inline uint16_t get_src_port() { return _tcp_hdr->src_port; }
inline uint8_t get_flags() { return _tcp_hdr->tcp_flags; }
inline uint16_t get_packet_size() { return _ip6_hdr->payload_len + 320; }
inline uint16_t get_payload_size() { return _ip6_hdr->payload_len - 20; }
inline uint16_t get_window_size() { return _tcp_hdr->rx_win; }
inline uint32_t get_seq_num() { return _tcp_hdr->sent_seq; }
inline uint32_t get_ack_num() { return _tcp_hdr->recv_ack; }
/**
* @brief NOT YET IMPLEMENTED FOR IPv6
* fills empty mbuf with IP and TCP header
* If this PacketInfo has a _mbuf and this _mbuf is empty,
* then all IP and TCP header information is filled in.
* This function doesn't create a new mbuf.
* @param src_ip IP address packet originally originated from
* @param dst_ip IP address packet is going to be send to
* @param src_port TCP port packet originally was send from
* @param dst_port TCP port packet should be recieved on
* @param seq_num TCP sequence number
* @param ack_num TCP acknowledgment number
* @param flags TCP flags wich are going to be set, can't set NS flag
*/
inline void fill_payloadless_tcp_packet(uint32_t src_ip, uint32_t dst_ip,
uint16_t src_port,
uint16_t dst_port, uint32_t seq_num,
uint32_t ack_num, uint8_t flags);
inline void re_calculate_checksums(); ///> NOT YET IMPLEMENTED FOR IPv6
private:
rte_ipv6_hdr* _ip6_hdr;
rte_tcp_hdr* _tcp_hdr;
};

View File

@@ -0,0 +1,65 @@
/**
* @file PacketInfoIpv6Udp.hpp
* @author Tobias
* @brief class to provide packets IPv6 and UDP header information
* @date 2021-06-09
*
*/
#pragma once
#include <rte_byteorder.h>
#include <rte_ether.h>
#include <rte_icmp.h>
#include <rte_ip.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include <rte_tcp.h>
#include <rte_udp.h>
#include <stdexcept>
#include "PacketDissection/PacketInfo.hpp"
class PacketInfoIpv6Udp : public PacketInfo {
public:
inline PacketInfoIpv6Udp() { /*set_type(IPv6UDP);*/
}
inline void set_ip_hdr(rte_ipv6_hdr* ip6_hdr) { this->_ip6_hdr = ip6_hdr; }
inline void set_udp_hdr(rte_udp_hdr* udp_hdr) { this->_udp_hdr = udp_hdr; }
/// IPv6 Functions
inline uint32_t get_dst_ip() {
/*__uint128_t dest_ip = 0;
for (short i = 0; i < 16; i++){
dest_ip << 8; /// shift left to make space for next part
dest_ip = dest_ip + _ip6_hdr->dst_addr[i]; /// add next part
}*/
printf("PacketInfoIpv6Udp not yet implemented! ");
return 0;
}
inline uint32_t get_src_ip() {
/*__uint128_t src_ip = 0;
for (short i = 0; i < 16; i++){
src_ip << 8; /// shift left to make space for next part
src_ip = src_ip + _ip6_hdr->src_addr[i]; /// add next part
}*/
printf("PacketInfoIpv6Udp not yet implemented! ");
return 0;
}
inline uint16_t get_dst_port() { return _udp_hdr->dst_port; }
inline uint16_t get_src_port() { return _udp_hdr->src_port; }
inline uint16_t get_packet_size() { return _ip6_hdr->payload_len + 320; }
inline uint16_t get_payload_size() { return _ip6_hdr->payload_len - 8; }
private:
rte_ipv6_hdr* _ip6_hdr;
rte_udp_hdr* _udp_hdr;
};

View File

@@ -0,0 +1,198 @@
/**
* @file PacketProtTcp.hpp
* @author Tobias
* @brief class to extract and change some informations in TCP header
*
*/
#pragma once
#include <boost/log/trivial.hpp>
#include <rte_mbuf.h>
#include <rte_tcp.h>
#define FIN_FLAG_POS 0b00000001
#define SYN_FLAG_POS 0b00000010
#define RST_FLAG_POS 0b00000100
#define ACK_FLAG_POS 0b00010000
#define FIRST_4_BIT 0b11110000
#define TCP_HDR_SIZE_4BYTE_WORD 0b01010000
class PacketProtTcp {
public:
// PacketProtTcp(rte_tcp_hdr* tcp_hdr);
/**
* @brief Set packets TCP sequence number
*
* @param seq_num
*/
inline static void set_seq_num(rte_tcp_hdr* tcp_hdr, uint32_t seq_num) {
tcp_hdr->sent_seq = rte_cpu_to_be_32(seq_num);
}
/**
* @brief Set packets TCP acknowledgment number
*
* @param ack_num
*/
inline static void set_ack_num(rte_tcp_hdr* tcp_hdr, uint32_t ack_num) {
tcp_hdr->recv_ack = rte_cpu_to_be_32(ack_num);
}
/**
* @brief Get packets TCP destination port
*
* @return uint16_t
*/
inline static uint16_t get_dst_port(rte_tcp_hdr* tcp_hdr) {
return rte_be_to_cpu_16(tcp_hdr->dst_port);
}
/**
* @brief Get packets TCP source port
*
* @return uint16_t
*/
inline static uint16_t get_src_port(rte_tcp_hdr* tcp_hdr) {
return rte_be_to_cpu_16(tcp_hdr->src_port);
}
/**
* @brief Get packets TCP flags
* MSB is CWR flag, LSB is FIN flag, NS flag not included
* @return uint8_t
*/
inline static uint8_t get_flags(rte_tcp_hdr* tcp_hdr) {
return tcp_hdr->tcp_flags; // these are FIN to CWR flag, but i am not
// shure in which order
}
/**
* @brief Get packets TCP window size
*
* @return uint16_t
*/
inline static uint16_t get_window_size(rte_tcp_hdr* tcp_hdr) {
return rte_be_to_cpu_16(tcp_hdr->rx_win);
}
/**
* @brief Get packets TCP sequence number
*
* @return uint32_t
*/
inline static uint32_t get_seq_num(rte_tcp_hdr* tcp_hdr) {
return rte_be_to_cpu_32(tcp_hdr->sent_seq);
}
/**
* @brief Get packets TCP acknowledgment number
*
* @return uint32_t
*/
inline static uint32_t get_ack_num(rte_tcp_hdr* tcp_hdr) {
return rte_be_to_cpu_32(tcp_hdr->recv_ack);
}
/**
* @brief Get packets TCP-header length
*
* @return uint16_t
*/
inline static uint16_t get_tcp_hdr_len(rte_tcp_hdr* tcp_hdr) {
return (tcp_hdr->data_off & FIRST_4_BIT) * 4;
}
/**
* @brief Get packets TCP SYN flag
*
* @return true if flag is set
* @return false if flag is not set
*/
inline static bool get_syn_flag(rte_tcp_hdr* tcp_hdr) {
if ((tcp_hdr->tcp_flags & SYN_FLAG_POS) == SYN_FLAG_POS) {
return true;
} else {
return false;
}
}
/**
* @brief Get packets TCP ACK flag
*
* @return true if flag is set
* @return false if flag is not set
*/
inline static bool get_ack_flag(rte_tcp_hdr* tcp_hdr) {
if ((tcp_hdr->tcp_flags & ACK_FLAG_POS) == ACK_FLAG_POS) {
return true;
} else {
return false;
}
}
/**
* @brief Get packets TCP RST flag
*
* @return true if flag is set
* @return false if flag is not set
*/
inline static bool get_rst_flag(rte_tcp_hdr* tcp_hdr) {
if ((tcp_hdr->tcp_flags & RST_FLAG_POS) == RST_FLAG_POS) {
return true;
} else {
return false;
}
}
/**
* @brief Get packets TCP FIN flag
*
* @return true if flag is set
* @return false if flag is not set
*/
inline static bool get_fin_flag(rte_tcp_hdr* tcp_hdr) {
if ((tcp_hdr->tcp_flags & FIN_FLAG_POS) == FIN_FLAG_POS) {
return true;
} else {
return false;
}
}
/**
* @brief fills empty mbuf with IP and TCP header
* If this PacketInfo has a _mbuf and this _mbuf is empty,
* then all IP and TCP header information is filled in.
* This function doesn't create a new mbuf.
* @param src_ip IP address packet originally originated from
* @param dst_ip IP address packet is going to be send to
* @param src_port TCP port packet originally was send from
* @param dst_port TCP port packet should be reci#include <rte_ip.h>eved on
* @param seq_num TCP sequence number
* @param ack_num TCP acknowledgment number
* @param flags TCP flags wich are going to be set, can't set NS flag
* @param rx_win TCP recive side window
*/
inline static void
fill_payloadless_tcp_header(rte_tcp_hdr* tcp_hdr, rte_mbuf* mbuf,
uint16_t src_port, uint16_t dst_port,
uint32_t seq_num, uint32_t ack_num,
uint8_t flags, uint16_t rx_win) {
tcp_hdr->src_port = rte_cpu_to_be_16(src_port);
tcp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
tcp_hdr->sent_seq = rte_cpu_to_be_32(seq_num);
tcp_hdr->recv_ack = rte_cpu_to_be_32(ack_num);
tcp_hdr->data_off = TCP_HDR_SIZE_4BYTE_WORD;
tcp_hdr->tcp_flags = flags;
tcp_hdr->rx_win = rte_cpu_to_be_16(rx_win);
tcp_hdr->tcp_urp = 0;
tcp_hdr->cksum = 0;
}
inline static void fill_tcp_cksm(rte_tcp_hdr* tcp_hdr, uint16_t cksm) {
tcp_hdr->cksum = rte_cpu_to_be_16(cksm);
}
};

View File

@@ -0,0 +1,45 @@
/**
* @file PacketProtUdp.hpp
* @author Tobias
* @brief provide UDP specific functions
*
*/
#pragma once
#include <rte_byteorder.h>
#include <rte_ip.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include <rte_udp.h>
class PacketProtUdp {
public:
/**
* @brief Get packets UDP destination port
*
* @return uint16_t
*/
inline static uint16_t get_dst_port(rte_udp_hdr* const udp_hdr) {
return rte_be_to_cpu_16(udp_hdr->dst_port);
}
/**
* @brief Get packets UDP source port
*
* @return uint16_t
*/
inline static uint16_t get_src_port(rte_udp_hdr* const udp_hdr) {
return rte_be_to_cpu_16(udp_hdr->src_port);
}
inline static void fill_payloadless_udp_header(rte_udp_hdr* const udp_hdr,
uint16_t dst_port, uint16_t src_port) {
udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
udp_hdr->src_port = rte_cpu_to_be_16(src_port);
udp_hdr->dgram_len = rte_cpu_to_be_16(8);
udp_hdr->dgram_cksum = 0;
}
};

View File

@@ -0,0 +1,73 @@
#pragma once
#include <cstdlib>
#include <stdint.h>
/**
* @brief Generate random unassigned 16, 32 and 64 bit integer using
* XorShift algorithm and rand() for generating a seed.
*/
class RandomNumberGenerator {
public:
uint16_t _seed_x16;
uint32_t _seed_x32;
uint64_t _seed_x64;
/**
* @brief Construct a new Random Number Generator object
*/
inline RandomNumberGenerator()
: _seed_x16(rand()), _seed_x32(rand()), _seed_x64(rand()) {}
/**
* @brief generates a 16 bit unsigned integer between lower limit and
* upper limit (1024 and 49151 for valid port numbers)
*
* @return uint16_t
*/
inline uint16_t gen_rdm_16_bit_in_interval(uint16_t _lower_limit,
uint16_t _upper_limit) {
_seed_x16 ^= _seed_x16 << 7;
_seed_x16 ^= _seed_x16 >> 9;
_seed_x16 ^= _seed_x16 << 8;
// this method returns a valid port number
// range should be: 1024 to 49152
return _seed_x16 % (_upper_limit - _lower_limit) + _lower_limit;
}
/**
* @brief generates 16 bit unsigned integer
*
* @return uint16_t
*/
inline uint16_t gen_rdm_16_bit() {
_seed_x16 ^= _seed_x16 << 7;
_seed_x16 ^= _seed_x16 >> 9;
_seed_x16 ^= _seed_x16 << 8;
return _seed_x16;
}
/**
* @brief generates 32 bit unsigned integer
*
* @return uint32_t
*/
inline uint32_t gen_rdm_32_bit() {
_seed_x32 ^= _seed_x32 << 14;
_seed_x32 ^= _seed_x32 >> 13;
_seed_x32 ^= _seed_x32 << 15;
return _seed_x32;
}
/**
* @brief generates 64 bit unsigned integer
*
* @return uint64_t
*/
inline uint64_t gen_rdm_64_bit() {
_seed_x64 ^= _seed_x64 << 14;
_seed_x64 ^= _seed_x64 >> 23;
_seed_x64 ^= _seed_x64 << 33;
return _seed_x64;
}
};

View File

@@ -0,0 +1,449 @@
#pragma once
#include <rte_ether.h>
#include "PacketDissection/PacketContainerLean.hpp"
#include "PacketDissection/PacketInfo.hpp"
#include "PacketDissection/PacketInfoIpv4Tcp.hpp"
#include "RandomNumberGenerator.hpp"
#include "Threads/ForwardingThread.hpp"
class AttackThread : public Thread {
private:
inline void run() {
std::cout << "\nRunning on lcore " << rte_lcore_id()
<< ". [Ctrl+C to quit]\n"
<< std::endl;
while (likely(_quit == false)) {
// have skip iterate field in config and skip for nb of packets
iterate();
#ifdef SINGLE_ITERATION
_quit = false;
#endif
}
_running = false;
}
PacketContainerLean* _pkt_container_to_dave;
PacketContainerLean* _pkt_container_to_alice;
RandomNumberGenerator _rng;
unsigned int _nb_worker_threads;
rte_ether_addr _bob_mac;
rte_ether_addr _src_mac;
uint32_t _bob_ip;
uint32_t _alice_ip;
uint8_t _tcp_flags;
enum AttackType { SYN_FLOOD, SYN_FIN_ACK, SYN_FIN, UDP_FLOOD, NO_ATTACK };
AttackType _attack_type;
rte_mbuf* _mbuf_origin;
uint64_t _cycles_old;
uint64_t _data_rate;
uint64_t _nb_attack_packets;
uint64_t _data_rate_per_cycle;
uint64_t _delta_cycles_mean;
uint64_t _total_nb_pkts_to_dave;
uint64_t _total_nb_pkts_from_dave;
uint64_t _total_nb_pkts_to_alice;
uint64_t _total_data_volume_to_alice;
uint64_t _total_nb_pkts_from_alice;
uint64_t _total_data_volume_from_alice;
int _iterations;
uint _call_send_pkts_every_nth_iteration;
// ============ not needed
uint16_t _nb_pkts_to_dave;
uint16_t _nb_pkts_to_alice;
PacketType _pkt_type;
uint64_t _cycles;
uint64_t _delta_cycles;
uint64_t _data_volume;
uint64_t _hz;
int _n;
/**
* This method is used in a loop so every parameter is created before
* the loop. These you pass to the function which initializes the
* variables.
*
* @param[in] pkt_size
* @param[in] cycles
* @param[in] delta_cycles
* @param[in] cycles_old
* @param[in] data_volume
* @param[in] data_rate_per_cycle
* @param[out] nb_attack_packets
*/
inline void calculate_nb_attack_packets(int pkt_size) {
_cycles = rte_get_tsc_cycles();
_delta_cycles = _cycles - _cycles_old;
// data volume to send in bit
_data_volume = _delta_cycles * _data_rate_per_cycle;
_nb_attack_packets = int(_data_volume / (pkt_size * 8));
if (unlikely(_nb_attack_packets == 0)) {
_nb_attack_packets = 2;
}
if (unlikely(_nb_attack_packets >= NUM_MBUF_ARRS * BURST_SIZE - 1)) {
_nb_attack_packets = NUM_MBUF_ARRS * BURST_SIZE - 1;
LOG_INFO << "maximum reached" << LOG_END;
}
LOG_INFO << "Number of cycles: " << _delta_cycles << LOG_END;
LOG_INFO << "Duration of a period: " << (_delta_cycles / _hz)
<< LOG_END;
// set _cycles_old
_cycles_old = _cycles;
}
/**
* @brief
*
* @param byte1
* @param byte2
* @param byte3
* @param byte4
* @return uint32_t
*/
inline uint32_t calculate_ipv4_address(uint8_t byte1, uint8_t byte2,
uint8_t byte3, uint8_t byte4) {
return byte1 * 2 ^ 24 + byte2 * 2 ^ 16 + byte3 * 2 ^ 8 + byte4;
}
/**
* @brief Create a bulk of attack packets, add them to the packets
* already in the PacketContainer.
*/
inline void create_attack_packet_burst_tcp(uint32_t nb_pkts,
uint8_t tcp_flags) {
rte_mempool* mempool = _pkt_container_to_dave->get_mempool_lean();
rte_mbuf* m_copy;
for (int i = 0; i < nb_pkts; ++i) {
m_copy = rte_pktmbuf_copy(_mbuf_origin, mempool, 0, UINT32_MAX);
if (unlikely(m_copy == nullptr)) {
throw std::runtime_error("m_copy is null");
}
PacketInfoIpv4Tcp* pkt_info = static_cast<PacketInfoIpv4Tcp*>(
PacketInfoCreator::create_mini_pkt_info(m_copy, IPv4TCP));
pkt_info->set_src_ip(_rng.gen_rdm_32_bit());
// select one of the following two, which one suits you better
// pkt_info->recalculate_checksums();
pkt_info->prepare_offloading_checksums();
_pkt_container_to_dave->add_mbuf(m_copy);
delete pkt_info;
pkt_info = nullptr;
}
}
/**
* @brief Create a bulk of attack packets, add them to the packets
* already in the PacketContainer.
*/
inline void create_attack_packet_burst_udp(uint32_t nb_pkts) {
rte_mempool* mempool = _pkt_container_to_dave->get_mempool_lean();
rte_mbuf* m_copy;
for (int i = 0; i < nb_pkts; ++i) {
m_copy = rte_pktmbuf_copy(_mbuf_origin, mempool, 0, UINT32_MAX);
if (unlikely(m_copy == nullptr)) {
throw std::runtime_error("m_copy is null");
}
PacketInfoIpv4Udp* pkt_info = static_cast<PacketInfoIpv4Udp*>(
PacketInfoCreator::create_mini_pkt_info(m_copy, IPv4UDP));
pkt_info->set_src_ip(_rng.gen_rdm_32_bit());
// select one of the following two, which one suits you better
// pkt_info->recalculate_checksums();
pkt_info->prepare_offloading_checksums(false);
_pkt_container_to_dave->add_mbuf(m_copy);
delete pkt_info;
pkt_info = nullptr;
}
}
inline void calculate_cycles() {
_cycles = rte_get_tsc_cycles();
_delta_cycles = _cycles - _cycles_old;
if (_n == 1) {
_delta_cycles_mean = _delta_cycles;
}
_delta_cycles_mean =
(_delta_cycles_mean + _delta_cycles / _n) * _n / (_n + 1);
++_n;
LOG_INFO << "delta_cycles_mean: " << _delta_cycles_mean << LOG_END;
// LOG_INFO << "Duration of a period: " << (_delta_cycles / _hz) <<
// LOG_END;
_cycles_old = _cycles;
}
public:
bool _do_attack;
inline AttackThread(PacketContainerLean* pkt_container_to_dave,
PacketContainerLean* pkt_container_to_alice,
unsigned int nb_worker_threads)
: Thread(), _nb_worker_threads(nb_worker_threads), _iterations(0),
_call_send_pkts_every_nth_iteration(0),
_pkt_container_to_dave(pkt_container_to_dave),
_pkt_container_to_alice(pkt_container_to_alice), _nb_pkts_to_dave(0),
_nb_pkts_to_alice(0), _total_nb_pkts_to_dave(0),
_total_nb_pkts_from_dave(0), _total_nb_pkts_to_alice(0),
_total_data_volume_to_alice(0), _total_nb_pkts_from_alice(0),
_total_data_volume_from_alice(0), _pkt_type(NONE), _cycles(0),
_delta_cycles(0), _data_volume(0), _nb_attack_packets(0),
_hz(rte_get_tsc_hz()), _delta_cycles_mean(0), _n(1),
_bob_mac({.addr_bytes = {60, 253, 254, 163, 231, 48}}),
_src_mac({.addr_bytes = {60, 253, 254, 163, 231, 88}}),
_bob_ip(167772162), _alice_ip(167772161), _tcp_flags(0),
_mbuf_origin(nullptr), _do_attack(false) {
// ===== calculate stuff regarding clock calculation ===== //
/*
_data_rate =
int((std::stoi(Configurator::instance()->get_config_as_string(
"attack_rate")) *
1000000) /
_nb_worker_threads);
_data_rate_per_cycle = int(_data_rate / _hz);
// if data_rate < hz
if (_data_rate_per_cycle == 0) {
_data_rate_per_cycle = _data_rate;
}
_cycles_old = rte_get_tsc_cycles();
*/
// ===== read and set attack type =====//
std::string attack_type =
Configurator::instance()->get_config_as_string("attack_type");
if (attack_type == "none") {
_attack_type = NO_ATTACK;
} else if (attack_type == "syn_flood") {
_attack_type = SYN_FLOOD;
_tcp_flags = 0b00000010;
} else if (attack_type == "syn_fin") {
_attack_type = SYN_FIN;
_tcp_flags = 0b00000011;
} else if (attack_type == "syn_fin_ack") {
_attack_type = SYN_FIN_ACK;
_tcp_flags = 0b00010011;
} else if (attack_type == "udp_flood") {
_attack_type = UDP_FLOOD;
} else {
throw std::runtime_error(
"String attack_type in config_attacker.json "
"does not match any type");
}
LOG_INFO << "Attack type " << attack_type << " is set." << LOG_END;
// =====set number of attack packets =====//
_nb_attack_packets =
Configurator::instance()->get_config_as_unsigned_int(
"number_of_attack_packets_per_thread_per_send_call");
_call_send_pkts_every_nth_iteration =
Configurator::instance()->get_config_as_unsigned_int(
"call_send_pkts_every_nth_iteration");
LOG_INFO << "number_of_attack_packets_per_thread_per_send_call : "
<< _nb_attack_packets << LOG_END;
//===== create origin attack packet=====//
_mbuf_origin =
rte_pktmbuf_alloc(_pkt_container_to_dave->get_mempool_lean());
if (_attack_type == SYN_FLOOD || _attack_type == SYN_FIN ||
_attack_type == SYN_FIN_ACK) {
PacketInfo* pkt_info_plain =
PacketInfoCreator::create_pkt_info(_mbuf_origin, IPv4TCP);
PacketInfoIpv4Tcp* pkt_info_origin =
static_cast<PacketInfoIpv4Tcp*>(pkt_info_plain);
pkt_info_origin->fill_payloadless_tcp_packet(
_src_mac, _bob_mac, _rng.gen_rdm_32_bit(), _bob_ip,
_rng.gen_rdm_16_bit(), 80, 1, 1, _tcp_flags, 64);
pkt_info_origin->prepare_offloading_checksums();
delete pkt_info_origin;
pkt_info_origin = nullptr;
} else if (_attack_type == UDP_FLOOD) {
PacketInfo* pkt_info_plain =
PacketInfoCreator::create_pkt_info(_mbuf_origin, IPv4UDP);
PacketInfoIpv4Udp* pkt_info_origin =
static_cast<PacketInfoIpv4Udp*>(pkt_info_plain);
pkt_info_origin->fill_payloadless_udp_packet(
_src_mac, _bob_mac, _rng.gen_rdm_32_bit(), _bob_ip,
_rng.gen_rdm_16_bit(), 80);
pkt_info_origin->prepare_offloading_checksums(false);
delete pkt_info_origin;
pkt_info_origin = nullptr;
}
// =====attack rate
}
inline ~AttackThread() { rte_pktmbuf_free(_mbuf_origin); }
inline static int s_run(void* thread_vptr) {
AttackThread* thread = static_cast<AttackThread*>(thread_vptr);
thread->run();
return 0;
}
inline void iterate() {
// ===== ALICE <--[MALLORY]-- DAVE/BOB ===== //
_pkt_container_to_alice->poll_mbufs(_nb_pkts_to_alice);
_total_nb_pkts_from_dave += _nb_pkts_to_alice;
// continue if no packets are received
if (likely(_nb_pkts_to_alice > 0)) {
// drop all packets that do not go to the mallory interface
for (int i = 0; i < _nb_pkts_to_alice; i++) {
rte_mbuf* mbuf = _pkt_container_to_alice->get_mbuf_at_index(i);
uint32_t ip4_addr =
PacketInfoCreator::get_dst_ip_from_mbuf(mbuf);
if (likely(ip4_addr != 0 && ip4_addr != _alice_ip)) {
_pkt_container_to_alice->drop_polled_mbuf(i);
} else {
_total_data_volume_to_alice += rte_pktmbuf_pkt_len(mbuf);
}
}
_total_nb_pkts_to_alice += _pkt_container_to_alice->send_mbufs();
}
// ===== ALICE --[MALLORY]--> DAVE/BOB ===== //
_pkt_container_to_dave->poll_mbufs(_nb_pkts_to_dave);
_total_nb_pkts_from_alice += _nb_pkts_to_dave;
for (int i = 0; i < _nb_pkts_to_dave; ++i) {
_total_data_volume_from_alice += rte_pktmbuf_pkt_len(
_pkt_container_to_dave->get_mbuf_at_index(i));
}
if (unlikely(_iterations == _call_send_pkts_every_nth_iteration)) {
_iterations = 0;
// create attack packets
if (likely(_do_attack)) {
if (_attack_type == SYN_FLOOD || _attack_type == SYN_FIN ||
_attack_type == SYN_FIN_ACK) {
create_attack_packet_burst_tcp(_nb_attack_packets,
_tcp_flags);
} else if (_attack_type == UDP_FLOOD) {
create_attack_packet_burst_udp(_nb_attack_packets);
}
} else{
_total_nb_pkts_to_dave = 0;
_total_nb_pkts_from_dave = 0;
_total_nb_pkts_to_alice = 0;
_total_data_volume_to_alice = 0;
_total_nb_pkts_from_alice = 0;
_total_data_volume_from_alice = 0;
}
}
++_iterations;
_total_nb_pkts_to_dave = _total_nb_pkts_to_dave +
_pkt_container_to_dave->send_mbufs();
// calculate_cycles();
}
inline uint64_t get_total_nb_pkts_to_dave() {
return _total_nb_pkts_to_dave;
}
inline uint64_t get_total_nb_pkts_from_dave() {
return _total_nb_pkts_from_dave;
}
inline uint64_t get_total_nb_pkts_to_alice() {
return _total_nb_pkts_to_alice;
}
inline uint64_t get_total_data_volume_to_alice() {
return _total_data_volume_to_alice;
}
inline uint64_t get_total_nb_pkts_from_alice() {
return _total_nb_pkts_from_alice;
}
inline uint64_t get_total_data_volume_from_alice() {
return _total_data_volume_from_alice;
}
inline int get_atk_pkt_type() {
if ((_attack_type == SYN_FLOOD) || (_attack_type == SYN_FIN) ||
(_attack_type == SYN_FIN_ACK)) {
return 1;
}
return 0;
}
};

View File

@@ -0,0 +1,51 @@
#pragma once
#include "PacketDissection/PacketContainer.hpp"
#include "Treatment/Treatment.hpp"
#include "Threads/ForwardingThread.hpp"
class DefenseThread : public Thread {
public:
DefenseThread(MbufContainerReceiving* mbuf_container_from_inside,
MbufContainerReceiving* mbuf_container_from_outside,
MbufContainerTransmitting* mbuf_container_to_inside,
MbufContainerTransmitting* mbuf_container_to_outside);
~DefenseThread() { delete _treatment; }
void start_treat() { _do_treat = true; }
void stop_treat() { _do_treat = false; }
bool _do_treat;
/**
* @brief Wrapper for the run-method
*
* Static method that calls the run method on a specific thread
* object. This is necessary since s_run is used to start a new thread with
* the dpdk function "rte_eal_remote_launch" which only takes specific types
* of funktions.
*
* @param thread_obj object of type thread the run method is to be called on
* @return int
*/
static int s_run(void* thread_obj);
private:
Treatment* _treatment;
MbufContainerReceiving* _mbuf_container_from_outside;
MbufContainerReceiving* _mbuf_container_from_inside;
MbufContainerTransmitting* _mbuf_container_to_outside;
MbufContainerTransmitting* _mbuf_container_to_inside;
/**
* @brief Run thread
*
* "Main"-routine of a thread. It is executed until the application is quit
* or killed.
*/
void run();
};

View File

@@ -0,0 +1,41 @@
#pragma once
#include "PacketDissection/PacketContainer.hpp"
#include "PacketDissection/PacketContainerLean.hpp"
#include "Threads/Thread.hpp"
class ForwardingThread : public Thread {
public:
/**
* @brief Construct a new Thread object
*
* @param pkt_container_to_inside PacketContainer of packets that come from
* the outside port and are to be forwarded to the inside port
* @param pkt_container_to_outside PacketContainer of packets that come from
* the inside port and are to be forwarded to the outside port
*/
ForwardingThread(PacketContainer* pkt_container_to_inside,
PacketContainer* pkt_container_to_outside)
: Thread(), _pkt_container_to_inside(pkt_container_to_inside),
_pkt_container_to_outside(pkt_container_to_outside) {}
ForwardingThread(PacketContainerLean* pkt_container_to_inside,
PacketContainerLean* pkt_container_to_outside)
: Thread(), _pkt_container_to_inside_lean(pkt_container_to_inside),
_pkt_container_to_outside_lean(pkt_container_to_outside) {}
protected:
/**
* @brief in AttackThread: to dave
*/
PacketContainer* _pkt_container_to_inside;
PacketContainerLean* _pkt_container_to_inside_lean;
// PacketContainerLean* _pkt_container_from_outside_lean;
/**
* @brief in AttackThread: to alice
*/
PacketContainer* _pkt_container_to_outside;
PacketContainerLean* _pkt_container_to_outside_lean;
};

View File

@@ -0,0 +1,43 @@
#pragma once
#include <rte_ring_core.h>
#include <rte_ring_elem.h>
#include <string>
#include "Threads/Thread.hpp"
struct Stats {
uint64_t attacks;
uint64_t bytes;
uint64_t dropped;
uint64_t packets;
uint64_t work_time;
uint64_t syn_level;
Stats* operator+=(const Stats* new_stats);
};
struct StatsMonitor {
double attacks_per_second;
double attacks_percent;
double bytes_per_second;
double dropped_per_second;
double dropped_percent;
double packets_per_second;
double proc_speed; // process speed
double total_time;
};
class StatisticsThread : public Thread {
public:
static int s_run(void* thread_vptr);
void enqueue_statistics(int& id, Stats* new_stats);
void update_statistics(Stats* new_stats);
private:
void run();
static rte_ring* _s_queue[16];
static Stats* _s_stats;
};

View File

@@ -0,0 +1,23 @@
#pragma once
#include <stdint.h>
class Thread {
public:
/**
* @brief Construct a new Thread object
*/
inline Thread() : _quit(false), _running(true) {}
/**
* @brief quit the thread
*/
inline void quit() { _quit = true; }
inline bool is_running() { return _running; }
protected:
bool _quit;
bool _running;
uint64_t _cycles_old;
};

View File

@@ -0,0 +1,904 @@
#pragma once
#include "PacketDissection/MbufContainer.hpp"
#include "PacketDissection/MbufContainerReceiving.hpp"
#include "PacketDissection/MbufContainerTransmitting.hpp"
#include "PacketDissection/PacketContainer.hpp"
#include "PacketDissection/PacketInfo.hpp"
#include "PacketDissection/PacketInfoIpv4Tcp.hpp"
#include "rand.hpp"
#include "xxh3.hpp"
#include "xxhash.hpp"
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <list>
#include <sparsehash/dense_hash_map>
/**
* @file Treatment.h
* @author Fabienne, Felix, Tim
* @brief This header file includes the class structure, structs and needed
* includes
* @version 0.1
* @date 2021-06-10
*
* @copyright Copyright (c) 2021
*
*/
enum _flag_enum {
SYN = 0b00000010,
RST = 0b00000100,
FIN = 0b00000001,
ACK = 0b00010000,
FINACK = 0b00010001,
SYNACK = 0b00010010,
SYNFIN = 0b00000011
};
/**
* @brief Data struct used as the key in the _densemap.
*
* This Data struct is used as the key in the densemap. The parameters uniquely
* identify each connection, and are therefore satisfying the requirements of
* being a key in the densemap.
* @param _extip Stores the IP Address of the external host
* @param _intip Stores the IP Address of the internal host
* @param _extport Stores the Port Address of the external host
* @param _intport Stores the Port Address of the internal host
*
*/
class Data {
public:
u_int32_t _extip;
u_int32_t _intip;
u_int16_t _extport;
u_int16_t _intport;
/**
* @brief Construct a new Data object from scratch
*
*/
Data()
: _extip(0)
, _intip(0)
, _extport(0)
, _intport(0) {}
/**
* @brief Construct a new Data object
*
* @param _extip IP Address of external system
* @param _intip IP Address of internal system
* @param _extport Port of external system
* @param _intport Port of internal system
*/
Data(u_int32_t _extip, u_int32_t _intip, u_int16_t _extport,
u_int16_t _intport)
: _extip(_extip)
, _intip(_intip)
, _extport(_extport)
, _intport(_intport) {}
/**
* @brief Redefinition of operator==
* Needed in order to satisfy the external implementation of the used
* hashfunction in combination with googles densemap
*
* @param d1
* @return true
* @return false
*/
bool operator==(const Data& d1) const {
return d1._extip == _extip && d1._intip == _intip &&
d1._intport == _intport && d1._extport == _extport;
}
};
/**
*
* @brief Info Struct used to encode the _offset and wether a finack has been
* seen
*
* @param _offset Stores the difference between Sequence- and ACK-Numbers
* @param _finseen Stores if a fin has already been seen
* @param _pkt_inf Stores the PacketInfo for an ACK from connection
* establishment
*/
class Info {
public:
int _offset;
bool _finseen_to_inside;
bool _finseen_to_outside;
bool _ack_to_inside_expected;
bool _ack_to_outside_expected;
std::list<PacketInfoIpv4Tcp*> _pkt_inf_list;
/**
* @brief Construct a new Info object from scratch
*
*/
Info()
: _offset(0)
, _finseen_to_inside(false)
, _finseen_to_outside(false)
, _ack_to_inside_expected(false)
, _ack_to_outside_expected(false)
, _pkt_inf_list() {}
/**
* @brief Construct a new Info object
* @param _offset Stores the difference between Sequence- and ACK-Numbers
* @param _finseen Stores if a fin has already been seen
* @param _pkt_inf Stores the PacketInfo for an ACK from connection
* establishment
*/
Info(int offset, bool finseen_to_inside, bool finseen_to_outside,
bool ack_to_inside, bool ack_to_outside, PacketInfoIpv4Tcp* pkt_inf)
: _offset(offset)
, _finseen_to_inside(finseen_to_inside)
, _finseen_to_outside(finseen_to_outside)
, _ack_to_inside_expected(ack_to_inside)
, _ack_to_outside_expected(ack_to_outside) {
if (pkt_inf != nullptr) {
_pkt_inf_list.push_back(pkt_inf);
}
}
};
/**
* @brief TreatmentHash manages the calculation of the hashvalue over a Data
* Struct and is used in the _densemap
*
*/
class TreatmentHash {
public:
/**
* @brief Redefinition of the operator() used in the _densemap and _ackmap
*
* @param d Data Struct with encodings of internal and external IPs and
* ports, which uniquely identify a connection
* @return size_t Hashvalue used as the key in both _dense- and _ackmap
*/
size_t operator()(const Data& d) const { // C++ call by reference
return XXH3_64bits_withSeed(
&d._extip, sizeof(d._extip),
XXH3_64bits_withSeed(
&d._intip, sizeof(d._intip),
XXH3_64bits_withSeed(
&d._extport, sizeof(d._extport),
XXH3_64bits(&d._intport, sizeof(d._intport)))));
}
};
/**
* @brief Treatment class, containing all functionality of the Treatment.
*
* The Treatment itself provides an implementation of SYN-cookies, combined with
* the functionalities of a TCP-Proxy, in order to migitate SYN-Floods. Other
* attacks just as SYN-FIN, SYN-FIN-ACK or the UDP-Flood are already migitated
* in the analyzer, as the analyzer already contains all the information to do
* this. Thus function calls are reduced, ultimatively resulting in a better
* performance.
*
*/
class Treatment {
public:
/**
* @brief Construct a new Treatment object
*
* On construction of a new Treatment object the _s_timestamp is set to its
* initial value, a random cookie_secret is calculated and the pointers to
* both PacketContainers are being stored in member variables.
* @param pkt_to_inside PacketContainer containing the packets with the
* destination being the secured network
* @param pkt_to_outside PacketContainer containing the packets with the
* destination being the internet
*/
inline Treatment(MbufContainerTransmitting* pkt_send_to_outside,
MbufContainerTransmitting* pkt_send_to_inside,
u_int8_t syn_thresh)
: _cookie_secret(Rand::get_random_64bit_value())
, _packet_to_inside(pkt_send_to_inside)
, _packet_to_outside(pkt_send_to_outside)
, _syn_thresh(syn_thresh)
, _skip_syn(0) {
// disables logging
/* auto corehandle = boost::log::core::get();
corehandle->set_logging_enabled(false); */
// Densemap requires you to set an empty key, which is never used by
// legit connections Dense_hash_map requires you call set_empty_key()
_densemap.set_empty_key(Data(0, 0, 0, 0));
// immediately after constructing the hash_map, and before calling any
// other dense_hash_map method
_densemap.set_deleted_key(Data(0, 0, 1, 1));
// BOOST_LOG_TRIVIAL(info) << "|---Init of Treatment done. Created
// cookie_secret, " "_s_timestamp and inserted empty and deleted
// key---|";
}
/**
* @brief Construct a new Treatment object for testing purposes, create a
* random cookie_secret and init the _s_timestamp
*
*/
inline Treatment() {
_cookie_secret = 0;
_s_timestamp = 0;
}
/**
* @brief This method checks if the packet to inside is suitable for
* treatment and treats it accordingly
*
* The function treat_packets_to_inside() works on two packetcontainers and
* iterates over all elements inside of them. If the packet is not yet
* deleted and if it is a TCPIPv4 packet, then treatment begins. Depending
* on the flag combinations in the TCPHeader further steps are being taken
* in order to fulfill the requirements, which are defined in the activity
* diagram "treat_packets()" as seen in the review document. treat_packets()
* involves adjustments of sequence and acknowledgement numbers, calculating
* and checking syn-cookies. Depending on internal rules packets can be
* forwarded, adjusted, stored and dropped on their way through the system.
*/
inline bool treat_packets_to_inside(PacketInfoIpv4Tcp* _pkt_info) {
// BOOST_LOG_TRIVIAL(info)<< "Size of densemap before to inside: " <<
// _densemap.size();
/************************************************************************
****Treatment of packets with direction towards the internal
*network****
************************************************************************/
// get packetInfo at current position
// check if packet has been deleted
// check wether packet is IPv4TCP
// get the flags of packet i as they will be needed a few times
u_int8_t _flags = _pkt_info->get_flags();
// SYN-ACK is set, simply forward the packet to the internal
// network and create an entry in the _densemap
if ((_flags & _flag_enum::SYNFIN) == _flag_enum::SYNFIN) {
rte_pktmbuf_free(_pkt_info->get_mbuf());
} else if ((_flags & _flag_enum::SYNACK) ==
_flag_enum::SYNACK) { // check wether the syn and ack
// flag is set
// BOOST_LOG_TRIVIAL(info) << "|---Received SYN-ACK from
// outside---|";
// just simply forward the packet to the internal network
// also create entry in the _densemap, with _offset
// difference =
// 0
Data insert(_pkt_info->get_src_ip(), _pkt_info->get_dst_ip(),
_pkt_info->get_src_port(), _pkt_info->get_dst_port());
Info info(0, false, false, false, false, nullptr);
_densemap.insert(std::make_pair(insert, info));
// BOOST_LOG_TRIVIAL(info) << "|---Created new entry for
// connection: _extip " << _pkt_info->get_src_ip() << " _extport: "
// << _pkt_info->get_src_port()<< " _intip: " <<
// _pkt_info->get_dst_ip() << " _intport: " <<
// _pkt_info->get_dst_port() << "---|"; place packet in the sending
// container to inside
_packet_to_inside->add_mbuf(_pkt_info->get_mbuf());
}
// SYN is set, generate cookie hash
else if ((_flags & _flag_enum::SYN) == _flag_enum::SYN) {
if (_skip_syn < _syn_thresh) {
++_skip_syn;
} else { // SYN to INSIDE
// BOOST_LOG_TRIVIAL(info) << "|---Received SYN to inside---|";
// BOOST_LOG_TRIVIAL(info) << "|---Mbuf is: " <<
// _pkt_info->get_mbuf() << "---|";
/* use this part to calculate the syn-cookie, create a new
* packet and send it back to the same side it came from */
u_int32_t _cookie = calc_cookie_hash(
_s_timestamp, _pkt_info->get_src_ip(),
_pkt_info->get_dst_ip(), _pkt_info->get_src_port(),
_pkt_info->get_dst_port());
// BOOST_LOG_TRIVIAL(info) << "|---Calculated cookie is: " <<
// _cookie << "---|";
_cookie = _cookie & 0xFFFFFF00; // got upper bits
u_int32_t _seqnum =
_cookie |
_s_timestamp; // got cookie + 8 bit _s_timestamp
// BOOST_LOG_TRIVIAL(info)<<
// "|---Calculated cookie with timestamp
// is: " << _seqnum << "---|";
// create the reply for the external connection/host
rte_mbuf* reply_mbuf = _packet_to_outside->get_empty_mbuf();
if (reply_mbuf == nullptr) {
return false;
}
rte_pktmbuf_append(reply_mbuf, sizeof(struct rte_ether_hdr) +
sizeof(struct rte_ipv4_hdr) +
sizeof(struct rte_tcp_hdr));
PacketInfoIpv4Tcp* reply = new PacketInfoIpv4Tcp(reply_mbuf);
// BOOST_LOG_TRIVIAL(info) << "|---The reply is of type: " <<
// reply->get_type() << "---|";
reply->fill_payloadless_tcp_packet(
_pkt_info->get_dst_mac(), _pkt_info->get_src_mac(),
_pkt_info->get_dst_ip(), _pkt_info->get_src_ip(),
_pkt_info->get_dst_port(), _pkt_info->get_src_port(),
_seqnum, _pkt_info->get_seq_num() + 1, _flag_enum::SYNACK,
_pkt_info->get_window_size());
reply->prepare_offloading_checksums();
// BOOST_LOG_TRIVIAL(info) << "|---Created SYN-ACK with Cookie:
// " << reply->get_seq_num()<< "---|"; BOOST_LOG_TRIVIAL(info)
// << " |---The new SYN-ACK goes with: extip: " <<
// reply->get_dst_ip()<< " extport: " << reply->get_dst_port()<<
// " intip: " << reply->get_src_ip() << " intport: " <<
// reply->get_src_port() << "---|"; delete/drop received
rte_pktmbuf_free(_pkt_info->get_mbuf());
// BOOST_LOG_TRIVIAL(info) << "|---Dropped incoming packet---|";
// now packet is getting send out in the next burst cycle
delete reply;
_skip_syn = 0;
}
}
// Case: RST received from outside
else if ((_flags & _flag_enum::RST) == _flag_enum::RST) {
// BOOST_LOG_TRIVIAL(info) << "|---Received RST from outside,
// ""deleting entry in densemap---|"; erase entry in _densemap with
// key = hash(AliceIP, AlicePort, BobIP, BobPort) Send packet to
// inside with destIP = BobIP, destPort = BobPort, srcIP = AliceIP,
// srcPort = AlicePort erased entry in _densemap
_densemap.erase(
Data(_pkt_info->get_src_ip(), _pkt_info->get_dst_ip(),
_pkt_info->get_src_port(), _pkt_info->get_dst_port()));
_packet_to_inside->add_mbuf(_pkt_info->get_mbuf());
}
// Case: Received FIN, no FIN-ACK from outside
else if (((_flags & _flag_enum::FIN) == _flag_enum::FIN)) {
// BOOST_LOG_TRIVIAL(info) << "|---Received a FIN from outside---|";
// create Data fin for the packet
// find the entry in our map
auto iter = _densemap.find(
Data(_pkt_info->get_src_ip(), _pkt_info->get_dst_ip(),
_pkt_info->get_src_port(), _pkt_info->get_dst_port()));
// Catch case, that we dont interact on empty map
if (iter == _densemap.end()) {
// drop packet
rte_pktmbuf_free(_pkt_info->get_mbuf());
// BOOST_LOG_TRIVIAL(info)<< "|---Dropped Packet comming from
// outside---|";
}
// Check if fin has already been seen, and we do not have an
// finack
else if (iter->second._finseen_to_outside == true) {
// BOOST_LOG_TRIVIAL(info) << "|---FIN-ACK to FIN received from
// outside---|"; change the packets ack number tweak by adding
// into one line
iter->second._finseen_to_inside = true;
iter->second._ack_to_outside_expected = true;
_pkt_info->set_ack_num(_pkt_info->get_ack_num() -
iter->second._offset);
_pkt_info->prepare_offloading_checksums();
// delete the entry
/* _densemap.erase(Data(
_pkt_info->get_src_ip(), _pkt_info->get_dst_ip(),
_pkt_info->get_src_port(),
_pkt_info->get_dst_port()));
//BOOST_LOG_TRIVIAL(info) << "Deleted entry in densemap";
*/
// send packet to inside // aka. do nothing
_packet_to_inside->add_mbuf(_pkt_info->get_mbuf());
} else if (iter->second._finseen_to_inside == false) {
// change status _finseen to true
iter->second._finseen_to_inside = true;
// change the packets ack number
_pkt_info->set_ack_num(_pkt_info->get_ack_num() -
iter->second._offset);
// refresh the checksums
_pkt_info->prepare_offloading_checksums();
// BOOST_LOG_TRIVIAL(info) << "|---Changed Finseen to true for
// connection: ""extip: " << _pkt_info->get_src_ip()
//<< " extport: " << _pkt_info->get_src_port()
//<< " intip: " << _pkt_info->get_dst_ip()
//<< " intport: " << _pkt_info->get_dst_port() << "---|";
_packet_to_inside->add_mbuf(_pkt_info->get_mbuf());
} else {
// BOOST_LOG_TRIVIAL(info) << "|---Duplicate FIN from
// Outside---|";
_pkt_info->set_ack_num(_pkt_info->get_ack_num() -
iter->second._offset);
// refresh the checksums
_pkt_info->prepare_offloading_checksums();
_packet_to_inside->add_mbuf(_pkt_info->get_mbuf());
}
}
// CASE: ACK RECEIVED from Alice
else if ((_flags & _flag_enum::ACK) == _flag_enum::ACK &&
((_flags & _flag_enum::FINACK) != _flag_enum::FINACK)) {
// BOOST_LOG_TRIVIAL(info) << "|---Received ACK from outside---|";
Data ack(_pkt_info->get_src_ip(), _pkt_info->get_dst_ip(),
_pkt_info->get_src_port(), _pkt_info->get_dst_port());
auto id = _densemap.find(ack);
if (id == _densemap.end()) { // no entry is here yet
// BOOST_LOG_TRIVIAL(info)
// << "|---Received ACK to SYN-ACK from outside---|";
// BOOST_LOG_TRIVIAL(info) << "|---Checking the SYN-COOKIE---|";
u_int32_t _cookie_val =
_pkt_info->get_ack_num(); // get acknowledgementnumber
// from packet
bool _legit =
check_syn_cookie(_cookie_val - 1,
ack); // check for the correkt cookie
if (_legit == true) { // the connection is to be established
// Take the packet and save it, till the connection
// to the internal host is established Use the
// densemap for this purpose by setting the pointer
// in info to taken_packet
rte_mbuf* reply_mbuf = _packet_to_inside->get_empty_mbuf();
if (reply_mbuf == nullptr) {
return false;
}
rte_pktmbuf_append(reply_mbuf,
sizeof(struct rte_ether_hdr) +
sizeof(struct rte_ipv4_hdr) +
sizeof(struct rte_tcp_hdr));
PacketInfoIpv4Tcp* reply =
new PacketInfoIpv4Tcp(reply_mbuf);
if (reply == nullptr) {
// BOOST_LOG_TRIVIAL(fatal) << "created a nullptr";
}
_densemap.insert(std::make_pair(
ack, Info(0, false, false, false, false, _pkt_info)));
// Still need to send that syn to inside
// TO-DO check if _pkt_info is legit there
reply->fill_payloadless_tcp_packet(
_pkt_info->get_src_mac(), _pkt_info->get_dst_mac(),
_pkt_info->get_src_ip(), _pkt_info->get_dst_ip(),
_pkt_info->get_src_port(), _pkt_info->get_dst_port(),
_pkt_info->get_seq_num() - 1, 123, _flag_enum::SYN,
_pkt_info->get_window_size());
reply->prepare_offloading_checksums();
// BOOST_LOG_TRIVIAL(info)
// << "|---Cookie " << _pkt_info->get_ack_num() - 1
// << " correct, sending SYN to inside---|";
// BOOST_LOG_TRIVIAL(info)
//<< "|---SYN to inside goes from " << reply->get_src_ip()
// << " to: " << reply->get_dst_ip() << " ---|";
// now packet is getting send out in the next burst
// cycle
_packet_to_outside->add_mbuf(reply_mbuf);
delete reply;
return true;
} else if (_legit == false) { // the connection is closed
// with an rst, drop packet
// BOOST_LOG_TRIVIAL(info)
// << "|---Cookie incorrect, dropped packet---|";
// Send RST if (diff>1 XOR hash!=cookie_value)
rte_mbuf* rst_mbuf = _packet_to_inside->get_empty_mbuf();
if (rst_mbuf == nullptr) {
return false;
}
PacketInfo* rst =
PacketInfoCreator::create_pkt_info(rst_mbuf, IPv4TCP);
PacketInfoIpv4Tcp* rst4 =
static_cast<PacketInfoIpv4Tcp*>(rst);
rst4->fill_payloadless_tcp_packet(
_pkt_info->get_dst_mac(), _pkt_info->get_src_mac(),
ack._extip, ack._intip, ack._extport, ack._intport,
_pkt_info->get_ack_num(), 0, _flag_enum::RST,
_pkt_info
->get_window_size()); // fill_payloadless_tcp_packet
// already exists, we
// just need it from
// Tobias
rst4->prepare_offloading_checksums();
_packet_to_outside->add_mbuf(rst4->get_mbuf());
rte_pktmbuf_free(_pkt_info->get_mbuf());
}
}
// No entry in _densemap -> It is an ACK as a reply to
// SYN-ACK entry can be found and its not a reply to an fin
// ack
else if (unlikely(id->second._finseen_to_inside == true &&
id->second._finseen_to_outside == true &&
id->second._ack_to_inside_expected == true)) {
// BOOST_LOG_TRIVIAL(info)
// << "|---ACK to FIN-ACK, Connection Closed---|";
// simply manage _offset and thats it
_pkt_info->set_ack_num(_pkt_info->get_ack_num() -
id->second._offset);
_pkt_info->prepare_offloading_checksums();
// delete the entry
_densemap.erase(id);
// BOOST_LOG_TRIVIAL(info) << "|---Deleted entry in
// densemap---|";
_packet_to_inside->add_mbuf(_pkt_info->get_mbuf());
}
// If the connection from inside is not fully established
// yet, i need to add it to the queue first
else if (unlikely(id->second._pkt_inf_list.empty() == false)) {
// now add it to the queue
// BOOST_LOG_TRIVIAL(info) << "|---Put early ack into
// queue---|";
id->second._pkt_inf_list.push_back(_pkt_info);
return true;
} else {
// BOOST_LOG_TRIVIAL(info) << "|---Regular ACK, simply
// send---|";
// simply manage _offset and thats it
_pkt_info->set_ack_num(_pkt_info->get_ack_num() -
id->second._offset);
_pkt_info->prepare_offloading_checksums();
_packet_to_inside->add_mbuf(_pkt_info->get_mbuf());
}
}
// BOOST_LOG_TRIVIAL(info) << "Size of densemap after to inside: " <<
// _densemap.size();
return false;
}
/**
* @brief This method checks if the packet to outside is suitable for
* treatment and treats it accordingly
*
* The function treat_packets_to_outside() works on two packetcontainers and
* iterates over all elements inside them. If the packet is not yet deleted
* and if it is a TCPIPv4 packet, then treatment begins. Depending on the
* flag combinations in the TCPHeader further steps are being taken in order
* to fulfill the requirements, which are defined in the activity diagram
* "treat_packets()" as seen in the review document. treat_packets()
* involves adjustments of sequence and acknowledgement numbers, calculating
* and checking syn-cookies. Depending on internal rules packets can be
* forwarded, adjusted, stored and dropped on their way through the system.
*/
inline bool treat_packets_to_outside(PacketInfoIpv4Tcp* _pkt_info) {
// BOOST_LOG_TRIVIAL(info) << "Size of densemap before to outside: " <<
// _densemap.size();
/************************************************************************
****Treatment of packets with direction towards the external network****
************************************************************************/
u_int8_t _flags =
_pkt_info->get_flags(); // get the flags of packet as
// they will be needed a few times
// BOOST_LOG_TRIVIAL(info) << "THE TYPE IS" << std::to_string(_flags);
if ((_flags & _flag_enum::SYNFIN) == _flag_enum::SYNFIN) {
rte_pktmbuf_free(_pkt_info->get_mbuf());
} else if ((_flags & _flag_enum::SYNACK) ==
_flag_enum::SYNACK) { // check wether the syn&ack flag is
// set
// BOOST_LOG_TRIVIAL(info) << "|---Got
// a SYN-ACK comming from inside---|";
// Create entry in the Densemap
// Reply with the ack stored in _densemap for this specific
// connection...
// Get Data from connection in order to create entry in
// _densemap and check _densemap
Data dfirst(_pkt_info->get_dst_ip(), _pkt_info->get_src_ip(),
_pkt_info->get_dst_port(), _pkt_info->get_src_port());
// find according value in _densemap
auto id = _densemap.find(dfirst);
// unsure about that, was to catch the case, that no ack has
// ever been held
if (id == _densemap.end()) {
// drop packet and delete connection info
rte_pktmbuf_free(_pkt_info->get_mbuf());
} else if (id->second._pkt_inf_list.empty() == false) {
// cast into an ipv4 packet
bool first_packet = true;
for (auto elem : id->second._pkt_inf_list) {
if (first_packet) {
// calculate _offset by substracting
// internal_ack_num from external_ack_num
int offset =
elem->get_ack_num() - _pkt_info->get_seq_num() - 1;
// BOOST_LOG_TRIVIAL(info) << "|---The offset is:" <<
// offset << ", the external acknum is: " <<
// elem->get_ack_num() << " the internal seqnum is: " <<
// _pkt_info->get_seq_num() << " --- |";
id->second._offset = offset;
// adjust the acknum of the ack as a response to
// syn ack
// outside->set_ack_num(outside->get_ack_num() -
// offset);
elem->set_ack_num(_pkt_info->get_seq_num() + 1);
// refresh checksum
elem->prepare_offloading_checksums();
// send received ack with adjusted acknum, this
// may already contain data
_packet_to_inside->add_mbuf(elem->get_mbuf());
// erase entry in _pkt_inf
first_packet = false;
} else {
elem->set_ack_num(elem->get_ack_num() -
id->second._offset);
elem->prepare_offloading_checksums();
_packet_to_inside->add_mbuf(elem->get_mbuf());
}
delete elem;
}
id->second._pkt_inf_list.clear();
} else {
// BOOST_LOG_TRIVIAL(fatal) << "No element in the list";
}
}
// check wether the syn flag is set
else if ((_flags & _flag_enum::SYN) == _flag_enum::SYN) {
// Simply forward the packet
// BOOST_LOG_TRIVIAL(info) << "|---Forwarding the " "SYN from
// internal to external ---|";
_packet_to_outside->add_mbuf(_pkt_info->get_mbuf());
}
// RST received from inside_pkt_
else if ((_flags & _flag_enum::RST) == _flag_enum::RST) {
// BOOST_LOG_TRIVIAL(info) << "|---Received an RST from inside---|";
Data erase(_pkt_info->get_dst_ip(), _pkt_info->get_src_ip(),
_pkt_info->get_dst_port(), _pkt_info->get_src_port());
auto id = _densemap.find(erase);
if (id == _densemap.end()) {
// drop packet
rte_pktmbuf_free(_pkt_info->get_mbuf());
} else {
_pkt_info->set_seq_num(_pkt_info->get_seq_num() +
id->second._offset);
_pkt_info->prepare_offloading_checksums();
_packet_to_outside->add_mbuf(_pkt_info->get_mbuf());
_densemap.erase(erase);
}
}
// FIN received from inside_pkt
else if (((_flags & _flag_enum::FIN) == _flag_enum::FIN)) {
// BOOST_LOG_TRIVIAL(info) << "|---Recevied a FIN from inside---|";
// create Data fin for the packet
// find the entry in our map
auto iter = _densemap.find(
Data(_pkt_info->get_dst_ip(), _pkt_info->get_src_ip(),
_pkt_info->get_dst_port(), _pkt_info->get_src_port()));
if (iter == _densemap.end()) {
// drop packet
rte_pktmbuf_free(_pkt_info->get_mbuf());
}
else if ((iter->second._finseen_to_inside == true) /* &&
((_flags & _flags::FINACK) == _flags::FINACK)*/) {
// Check if fin has already been seen and we are not
// looking for the reply
// BOOST_LOG_TRIVIAL(info) << "|---FIN-ACK for FIN---|";
// change the packets seq number
iter->second._finseen_to_outside = true;
iter->second._ack_to_inside_expected = true;
_pkt_info->set_seq_num(_pkt_info->get_seq_num() +
iter->second._offset);
_pkt_info->prepare_offloading_checksums();
// delete the entry
/* _densemap.erase(Data(
_pkt_info->get_dst_ip(), _pkt_info->get_src_ip(),
_pkt_info->get_dst_port(),
_pkt_info->get_src_port()));
*/
// send packet to inside // aka. do nothing
_packet_to_outside->add_mbuf(_pkt_info->get_mbuf());
}
// Case: its the first FIN with piggybagged ack
else if (iter->second._finseen_to_outside == false) {
// BOOST_LOG_TRIVIAL(info)<< "|---Recevied the first FIN from
// inside---|"; change status _finseen to true
iter->second._finseen_to_outside = true;
// get _offset
// change the packets seq number
_pkt_info->set_seq_num(_pkt_info->get_seq_num() +
iter->second._offset);
_pkt_info->prepare_offloading_checksums();
// BOOST_LOG_TRIVIAL(info) << "|---Changed Finseen to true for
// connection: " "extip: "
/* << _pkt_info->get_dst_ip()
<< " extport: " << _pkt_info->get_dst_port()
<< " intip: " << _pkt_info->get_src_ip()
<< " intport: " << _pkt_info->get_src_port() << "---|"; */
_packet_to_outside->add_mbuf(_pkt_info->get_mbuf());
} else {
// BOOST_LOG_TRIVIAL(info) << "|--- Saw duplicate FIN from
// outside----|";
_pkt_info->set_seq_num(_pkt_info->get_seq_num() +
iter->second._offset);
_pkt_info->prepare_offloading_checksums();
_packet_to_outside->add_mbuf(_pkt_info->get_mbuf());
}
}
// CASE: ACK RECEIVED from Bob
else if (((_flags & _flag_enum::ACK) == _flag_enum::ACK) &&
((_flags & _flag_enum::FINACK) != _flag_enum::FINACK)) {
// BOOST_LOG_TRIVIAL(info) << "|---Received an ACK from inside---|";
Data ack(_pkt_info->get_dst_ip(), _pkt_info->get_src_ip(),
_pkt_info->get_dst_port(), _pkt_info->get_src_port());
auto id = _densemap.find(ack);
// no entry in _densemap, create one and adjust value
// accordingly
if (id == _densemap.end()) {
// BOOST_LOG_TRIVIAL(info) << "|---Created new entry in the
// densemap---|";
Info info(0, false, false, false, false, nullptr);
_densemap.insert(std::make_pair(ack, info));
// send out packet, aka do nothing
_packet_to_outside->add_mbuf(_pkt_info->get_mbuf());
} else if (unlikely(id->second._finseen_to_inside == true &&
id->second._finseen_to_outside == true &&
id->second._ack_to_outside_expected == true)) {
// BOOST_LOG_TRIVIAL(info) << "|---ACK to FIN-ACK-Packet---|";
_pkt_info->set_seq_num(_pkt_info->get_seq_num() +
id->second._offset);
_pkt_info->prepare_offloading_checksums();
_densemap.erase(id);
// BOOST_LOG_TRIVIAL(info) << "|---Deleted entry in
// densemap--|";
_packet_to_outside->add_mbuf(_pkt_info->get_mbuf());
} else {
// BOOST_LOG_TRIVIAL(info) << "|---Just a regular
// ACK-Packet---|";
// it is just a regular packet, simply adjust with
// _offset and you are done.
_pkt_info->set_seq_num(_pkt_info->get_seq_num() +
id->second._offset);
_pkt_info->prepare_offloading_checksums();
_packet_to_outside->add_mbuf(_pkt_info->get_mbuf());
}
}
// BOOST_LOG_TRIVIAL(info) << "Size of densemap after to outside: " <<
// _densemap.size();
return false;
}
/**
* @brief used in the main_lcore timer, in order to increment the
* _s_timestamp every 64 seconds This function does nothing besides
* incrementing the _s_timestamp by one every time it is called from our
* thread
* @param timestamp is global, but changed by this function
*/
inline static void s_increment_timestamp() {
// increment _s_timestamp by one
++_s_timestamp;
}
private:
/**
* @brief Calculates the Cookiehash from the global _s_timestamp, a global
* cookie_secret and unique connection identifiers
*
* @param _s_timestamp is global
* @param _extip
* @param _intip
* @param _extport
* @param _intport
* @return u_int32_t
*/
inline u_int32_t calc_cookie_hash(u_int8_t _s_timestamp, u_int32_t _extip,
u_int32_t _intip, u_int16_t _extport,
u_int16_t _intport) {
// use XXH3_64bits as shrinking it is still faster than using XXH32
return XXH3_64bits_withSeed(
&_s_timestamp, sizeof(_s_timestamp),
XXH3_64bits_withSeed(
&_extip, sizeof(_extip),
XXH3_64bits_withSeed(
&_intip, sizeof(_intip),
XXH3_64bits_withSeed(
&_extport, sizeof(_extport),
XXH3_64bits_withSeed(&_intport, sizeof(_intport),
_cookie_secret)))));
}
/**
* @brief Check if the syn_cookie was received in the correct timespan and
* if the reveiced cookie is correct/like the expected cookie
*
* @param cookie_value This is the sequencenumber sent away in the syn-ack
* @param d d is the data we obtained from our packet, needed to calculate
* the expected hash
*
*/
inline bool check_syn_cookie(u_int32_t cookie_value, const Data& d) {
// Extract the last 8 bits of the cookie (= timestamp)
u_int8_t cookie_timestamp = cookie_value & 0x000000FF;
u_int8_t diff = _s_timestamp - cookie_timestamp;
if (diff <= 1) {
// Calculate hash
u_int32_t hash;
// Case: same time interval
if (diff == 0) {
// calculate expected cookie_hash
hash = calc_cookie_hash(_s_timestamp, d._extip, d._intip,
d._extport, d._intport);
hash = hash & 0xFFFFFF00;
// stuff cookie_hash with 8 bit _s_timestamp
hash |= (u_int8_t)_s_timestamp;
}
if (diff == 1) {
// calculate expected cookie_hash for older timeinterval
hash = calc_cookie_hash((u_int8_t)(_s_timestamp - 1), d._extip,
d._intip, d._extport, d._intport);
hash = hash & 0xFFFFFF00;
// stuff cookie with 8 bit _s_timestamp
hash |= (u_int8_t)(_s_timestamp - 1);
}
// test wether the cookie is as expected; if so, return true
if (hash == cookie_value) {
return true;
}
}
// return false, so that treat_packets is able to continue
return false;
}
inline static u_int8_t _s_timestamp =
0; ///< timestamp used to check the legitimacy of SYN-cookies
u_int64_t _cookie_secret; ///< cookie_secret used to enhance the efficency
///< of SYN-cookies
u_int8_t _skip_syn;
u_int8_t _syn_thresh;
MbufContainerTransmitting*
_packet_to_inside; ///< MbufContainer containing packets with
///< destination being the internal network
MbufContainerTransmitting*
_packet_to_outside; ///< MbufContainer containing packets with
///< destination being the extern network
google::dense_hash_map<Data, Info, TreatmentHash>
_densemap; ///< Map to store information about connections including
///< _offset and if a fin has been seen
friend class Treatment_friend; ///< used for unit tests
};

View File

@@ -0,0 +1,44 @@
#pragma once
/**
* @file rand.hpp
* @author Felix, Fabienne
* @brief This header includes only one method which returns a random 64bit
* unsigned integer
* @version 0.1
* @date 2021-07-06
*
* @copyright Copyright (c) 2021
*
*/
/**
* @brief Rand itself provides a method to get a random number. This number is
* used in Treatment as cookie_secret
*
*/
class Rand {
public:
/**
* @brief Get a random 64bit unsigned integer
*
* @return u_int64_t
*/
static u_int64_t get_random_64bit_value() {
u_int64_t random64BitNumber = 0;
u_int64_t value1 = (uint16_t)std::rand();
value1 = (value1 << 48);
random64BitNumber |= value1;
u_int64_t value2 = (uint16_t)rand();
value2 = (value2 << 32);
random64BitNumber |= value2;
u_int64_t value3 = (uint16_t)rand();
random64BitNumber |= value3;
return random64BitNumber;
}
};

View File

@@ -0,0 +1,54 @@
/*
* File: random.hpp
* --------------
* This interface exports functions for generating pseudorandom numbers.
*/
#ifndef _random_h
#define _random_h
/*
* Function: randomInteger
* Usage: int n = randomInteger(low, high);
* ----------------------------------------
* Returns a random integer in the range low to high, inclusive.
*/
int randomInteger(int low, int high);
/*
* Function: randomReal
* Usage: double d = randomReal(low, high);
* ----------------------------------------
* Returns a random real number in the half-open interval [low .. high). A
* half-open interval includes the first endpoint but not the second, which
* means that the result is always greater than or equal to low but
* strictly less than high.
*/
double randomReal(double low, double high);
/*
* Function: randomChance
* Usage: if (randomChance(p)) . . .
* ---------------------------------
* Returns true with the probability indicated by p. The argument p must
* be a floating-point number between 0 (never) and 1 (always). For
* example, calling randomChance(.30) returns true 30 percent of the time.
*/
bool randomChance(double p);
/*
* Function: setRandomSeed
* Usage: setRandomSeed(seed);
* ---------------------------
* Sets the internal random number seed to the specified value. You can
* use this function to set a specific starting point for the pseudorandom
* sequence or to ensure that program behavior is repeatable during the
* debugging phase.
*/
void setRandomSeed(int seed);
#endif

View File

@@ -0,0 +1,55 @@
/*
* xxHash - Extremely Fast Hash algorithm
* Development source file for `xxh3`
* Copyright (C) 2019-2020 Yann Collet
*
* BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at:
* - xxHash homepage: https://www.xxhash.com
* - xxHash source repository: https://github.com/Cyan4973/xxHash
*/
/*
* Note: This file used to host the source code of XXH3_* variants.
* during the development period.
* The source code is now properly integrated within xxhash.h.
*
* xxh3.h is no longer useful,
* but it is still provided for compatibility with source code
* which used to include it directly.
*
* Programs are now highly discouraged to include xxh3.h.
* Include `xxhash.h` instead, which is the officially supported interface.
*
* In the future, xxh3.h will start to generate warnings, then errors,
* then it will be removed from source package and from include directory.
*/
/* Simulate the same impact as including the old xxh3.h source file */
#define XXH_INLINE_ALL
#include "xxhash.hpp"

5325
include/Treatment/xxhash.hpp Normal file

File diff suppressed because it is too large Load Diff

25447
include/json.hpp Normal file

File diff suppressed because it is too large Load Diff