Skip to content

Commit

Permalink
SYN Flood Detector (#152)
Browse files Browse the repository at this point in the history
* pcn-synflood: datamodel and generated code

add datamodel draft
add stub for service

datamodel:
use uint64 everywhere, since float are not supported by yang
and decimal64 are not supported by our codegen toolchain

Signed-off-by: Matteo Bertrone <m.bertrone@gmail.com>

* pcn-synflood: implement get timestamp

Signed-off-by: Matteo Bertrone <m.bertrone@gmail.com>

* pcn-synflood: implement get metrics

Signed-off-by: Matteo Bertrone <m.bertrone@gmail.com>

* pcn-synflood: add test

Signed-off-by: Matteo Bertrone <m.bertrone@gmail.com>

* pcn-synflood: add documentation

Signed-off-by: Matteo Bertrone <m.bertrone@gmail.com>
Signed-off-by: Fulvio Risso <fulvio.risso@polito.it>
  • Loading branch information
mbertrone authored and acloudiator committed Jun 14, 2019
1 parent d8ddb44 commit 1cbb62c
Show file tree
Hide file tree
Showing 31 changed files with 2,848 additions and 0 deletions.
1 change: 1 addition & 0 deletions Documentation/services/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ This folder contains the list of services (a.k.a. *cubes*) currently available i
pcn-router/router
pcn-simplebridge/simplebridge
pcn-simpleforwarder/simpleforwarder
pcn-synflood/synflood
44 changes: 44 additions & 0 deletions Documentation/services/pcn-synflood/synflood.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
SYN Flood Monitor
=================

This service exports some metrics that can be used to detect a possible SYN Flood attack.


Features
--------
- Retrieves a set of TCP/IP parameters that can be used to detect SYN flooding attacks


Limitations
-----------
- It must be launched on the host that needs to be monitored. It cannot operate as a 'main in the middle' mode, i.e., inspecting network traffic directed toward a remote host.


How to use
----------
Technically, ``pcn-synflood`` is a transparent service, hence it should be attached to an existing network interface (e.g., netdev or a virtual link between Polycube services).
However, given that the current implementation retrieves traffic statistics using the metrics provided by the operating system, it can be even instantiated without attaching it to any network interface.


Exported metrics
----------------
- ``tcpAttemptFails``: number of failed TCP connections [1].
- ``tcpOutRsts``: number of TCP segments sent, containing RST flag.
- ``deliverRatio``: ratio between the number of IP pkts delivered to application protocols and the total number of received pkts.
- ``responseRatio``: ratio between the number of IP pkts requests to send by application protocols and the total number of received pkts.


Additional details
------------------

[1] ``tcpAttemptFails``

It measures the number of times TCP connections have made a direct transition to the CLOSED state from either the SYN-SENT state or the SYN-RCVD state, plus the number of times TCP connections have made a direct transition to the LISTEN state from the SYN-RCVD state. It refers to variable ``tcpAttemptFails`` documented in RFC 1213.

It is worth mentioning that this parameter is rather general and can be used to check for unusual situations on both client and server side. For instance, it can be used to detect either (1) that a server is under attack (e.g., TCP state machine goes from SYN-RCVD to LISTEN or CLOSED), or (2) that a client is currently attacking a remote target (e.g., TCP state machine goes from SYN-SENT to CLOSED).

The most common case, i.e., that a server is under attack, corresponds at least to the following unusual TCP sequences:
- [SYN, timeout]. The server receives a SYN packet, but it cannot answer any more because it is overwhelmed. This connection will be ended after server time‐out, as described earlier.
- [SYN (Client, Server), RST (Server, Client)]. This sequence means either that the server is the victim of a DoS attack because it cannot reply to the legitimate client any more, or that there is not applications listening on that port.
- [SYN, SYN/ACK, timeout]. The server waits indefinitely for the ACK packet, either because the IP source address is spoofed or because the ACK packet is rejected because of network congestion. This sequence can correspond to a DoS attack. This connection will be ended after server time‐out.
- [SYN, SYN/ACK, RST]. This handshake sequence can correspond to a DDoS attack. At the reception of the SYN/ACK packet, the client host then transmits an RST packet to the server because it never sent a SYN packet.
1 change: 1 addition & 0 deletions src/services/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ add_service(simplebridge pcn-simplebridge)
add_service(simpleforwarder pcn-simpleforwarder)
add_service(iptables pcn-iptables)
add_service(transparenthelloworld pcn-transparent-helloworld)
add_service(synflood pcn-synflood)

# save string to create code that load the services
SET_PROPERTY(GLOBAL PROPERTY LOAD_SERVICES_ ${LOAD_SERVICES})
Expand Down
13 changes: 13 additions & 0 deletions src/services/pcn-synflood/.swagger-codegen-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Swagger Codegen Ignore
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen

# Use this file to prevent files from being overwritten by the generator.

.swagger-codegen-ignore

src/*.cpp
src/*.h

!src/*Interface.h
!src/*JsonObject.h
!src/*JsonObject.cpp
5 changes: 5 additions & 0 deletions src/services/pcn-synflood/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cmake_minimum_required (VERSION 3.2)

set (CMAKE_CXX_STANDARD 11)

add_subdirectory(src)
52 changes: 52 additions & 0 deletions src/services/pcn-synflood/cmake/LoadFileAsVariable.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Loads the contents of a file into a std::string variable
#
# It creates a header file in ${CMAKE_CURRENT_BINARY_DIR}/${file}.h
# that wrapps the contents of the file in a std::string using the raw
# string literal feature of C++11. The user needs to include that file
# into the source code in order to see the variable.
#
# parameters:
# target: target to add a dependency on file
# file: file to be loaded
# variable_name: name variable where the file is loaded
#
# example:
# load_file_as_variable(my-lib resource.c my_resource)
# Creates a resource.h in CMAKE_CURRENT_BINARY_DIR with a string variable
# my_resource with the contents of resource.c
# A dependency in resource.c is added to my-lib

function(load_file_as_variable target file variable_name)
get_filename_component(file_name ${file} NAME_WE)
get_filename_component(file_dir ${file} DIRECTORY)

set(new_path ${file_dir}/${file_name}.h)

add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/${new_path}
COMMAND
mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${file_dir}
COMMAND
echo "#pragma once" > ${CMAKE_CURRENT_BINARY_DIR}/${new_path}
COMMAND
echo "#include <string>" >> ${CMAKE_CURRENT_BINARY_DIR}/${new_path}
COMMAND
echo "const std::string ${variable_name} = R\"POLYCUBE_DP(" >> ${CMAKE_CURRENT_BINARY_DIR}/${new_path}
COMMAND
cat ${CMAKE_CURRENT_SOURCE_DIR}/${file} >> ${CMAKE_CURRENT_BINARY_DIR}/${new_path}
COMMAND
cmake -E echo ")POLYCUBE_DP\";" >> ${CMAKE_CURRENT_BINARY_DIR}/${new_path}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file}
VERBATIM
)

string(REPLACE "/" "-" path_replaced ${new_path})

add_custom_target(
generate_${path_replaced}
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${new_path}
)

add_dependencies(${target} generate_${path_replaced})
endfunction()
53 changes: 53 additions & 0 deletions src/services/pcn-synflood/datamodel/synflood.yang
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
module synflood {
yang-version 1.1;
namespace "http://polycube.network/synflood";
prefix "synflood";

import polycube-base { prefix "polycube-base"; }
import polycube-transparent-base { prefix "polycube-transparent-base"; }

organization "Polycube open source project";
description "YANG data model for the Network Monitor";

polycube-base:service-description "TCP SYN Flood Monitor Service";
polycube-base:service-version "2.0";
polycube-base:service-name "synflood";
polycube-base:service-min-kernel-version "4.11.0";

uses "polycube-transparent-base:transparent-base-yang-module";

container stats {
description "Statistics for SYN Flood Monitor";
config false;

leaf tcpattemptfails {
type uint64;
description "TCP attempts fails";
config false;
}

leaf tcpoutrsts {
type uint64;
description "TCP sent with RST flag";
config false;
}

leaf deliverratio {
type uint64;
description "pkts delivered to application over total received pkts";
config false;
}

leaf responseratio {
type uint64;
description "pkts requests to send over total received pkts";
config false;
}

leaf lastupdate {
type uint64;
description "last update (time from epoch in milliseconds)";
config false;
}
}
}
48 changes: 48 additions & 0 deletions src/services/pcn-synflood/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
include(${PROJECT_SOURCE_DIR}/cmake/LoadFileAsVariable.cmake)

aux_source_directory(serializer SERIALIZER_SOURCES)
aux_source_directory(api API_SOURCES)
aux_source_directory(base BASE_SOURCES)

include_directories(serializer)

if (NOT DEFINED POLYCUBE_STANDALONE_SERVICE OR POLYCUBE_STANDALONE_SERVICE)
find_package(PkgConfig REQUIRED)
pkg_check_modules(POLYCUBE libpolycube)
include_directories(${POLYCUBE_INCLUDE_DIRS})
endif(NOT DEFINED POLYCUBE_STANDALONE_SERVICE OR POLYCUBE_STANDALONE_SERVICE)

# Needed to load files as variables
include_directories(${CMAKE_CURRENT_BINARY_DIR})

add_library(pcn-synflood SHARED
${SERIALIZER_SOURCES}
${API_SOURCES}
${BASE_SOURCES}
Stats.cpp
Synflood.cpp
Synflood-lib.cpp
Utils.cpp)

# load ebpf datapath code a variable
load_file_as_variable(pcn-synflood
Synflood_dp.c
synflood_code)

# load datamodel in a variable
load_file_as_variable(pcn-synflood
../datamodel/synflood.yang
synflood_datamodel)

target_link_libraries(pcn-synflood ${POLYCUBE_LIBRARIES})

# Specify shared library install directory

set(CMAKE_INSTALL_LIBDIR /usr/lib)

install(
TARGETS
pcn-synflood
DESTINATION
"${CMAKE_INSTALL_LIBDIR}"
)
78 changes: 78 additions & 0 deletions src/services/pcn-synflood/src/Stats.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* synflood API generated from synflood.yang
*
* NOTE: This file is auto generated by polycube-codegen
* https://github.com/polycube-network/polycube-codegen
*/


// TODO: Modify these methods with your own implementation


#include "Stats.h"
#include "Synflood.h"


Stats::Stats(Synflood &parent, const StatsJsonObject &conf)
: StatsBase(parent) {
}

Stats::~Stats() {}

const uint64_t ratioMultiplier = 1000;

uint64_t Stats::getTcpattemptfails() {
try {
return std::stoull(Synflood::exec("nstat -a | grep TcpAttemptFails | awk '{print $2}'"));
} catch (...) {
return 0;
}
}

uint64_t Stats::getTcpoutrsts() {
try {
return std::stoull(Synflood::exec("nstat -a | grep TcpOutRsts | awk '{print $2}'"));
} catch (...) {
return 0;
}
}

uint64_t Stats::getDeliverratio() {
try {
std::istringstream ipInDeliversStream(Synflood::exec("nstat -a | grep IpInDelivers | awk '{print $2}'"));
std::istringstream ipInReceivesStream(Synflood::exec("nstat -a | grep IpInReceives | awk '{print $2}'"));

uint64_t ipInDelivers;
uint64_t ipInReceives;

ipInDeliversStream >> ipInDelivers;
ipInReceivesStream >> ipInReceives;

float ratio = ((float) ipInDelivers / ((float) ipInReceives + 1.0)) * ratioMultiplier;
return (uint64_t) (ratio);
} catch (...) {
return 0;
}
}

uint64_t Stats::getResponseratio() {
try {
std::istringstream ipOutRequestsStream(Synflood::exec("nstat -a | grep IpOutRequests | awk '{print $2}'"));
std::istringstream ipInReceivesStream(Synflood::exec("nstat -a | grep IpInReceives | awk '{print $2}'"));

uint64_t ipOutRequests;
uint64_t ipInReceives;

ipOutRequestsStream >> ipOutRequests;
ipInReceivesStream >> ipInReceives;

float ratio = ((float)ipOutRequests / ((float)ipInReceives + 1.0)) * ratioMultiplier;
return (uint64_t)(ratio);
} catch (...) {
return 0;
}
}

uint64_t Stats::getLastupdate() {
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
48 changes: 48 additions & 0 deletions src/services/pcn-synflood/src/Stats.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* synflood API generated from synflood.yang
*
* NOTE: This file is auto generated by polycube-codegen
* https://github.com/polycube-network/polycube-codegen
*/


#pragma once


#include "../base/StatsBase.h"


class Synflood;

using namespace polycube::service::model;

class Stats : public StatsBase {
public:
Stats(Synflood &parent, const StatsJsonObject &conf);
virtual ~Stats();

/// <summary>
/// TCP attempts fails
/// </summary>
uint64_t getTcpattemptfails() override;

/// <summary>
/// TCP sent with RST flag
/// </summary>
uint64_t getTcpoutrsts() override;

/// <summary>
/// pkts delivered to application over total received pkts
/// </summary>
uint64_t getDeliverratio() override;

/// <summary>
/// pkts requests to send over total received pkts
/// </summary>
uint64_t getResponseratio() override;

/// <summary>
/// last update (time from epoch in milliseconds)
/// </summary>
uint64_t getLastupdate() override;
};
21 changes: 21 additions & 0 deletions src/services/pcn-synflood/src/Synflood-lib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* synflood API generated from synflood.yang
*
* NOTE: This file is auto generated by polycube-codegen
* https://github.com/polycube-network/polycube-codegen
*/


/* Do not edit this file manually */

#include "api/SynfloodApiImpl.h"
#include "../datamodel/synflood.h" // generated from datamodel

#define SERVICE_PYANG_GIT ""
#define SERVICE_SWAGGER_CODEGEN_GIT "GIT_REPO_ID"

#include <polycube/services/shared_library.h>

extern "C" const char *data_model() {
return synflood_datamodel.c_str();
}

0 comments on commit 1cbb62c

Please sign in to comment.