├── .gitignore ├── CMakeLists.txt ├── README.md ├── configs ├── example.lua └── example_watchedips.xml ├── screenshot.png ├── scripts ├── ipblock ├── networkcompromise └── notificate └── src ├── .gitignore ├── configmanager.cpp ├── configmanager.h ├── ddos.cpp ├── ddos.h ├── ddosmon.cpp ├── dispatcher.cpp ├── dispatcher.h ├── headers.h ├── ipswitcher.cpp ├── ipswitcher.h ├── logger.cpp ├── logger.h ├── monitor.cpp ├── monitor.h ├── packet.cpp ├── packet.h ├── scheduler.cpp ├── scheduler.h ├── screen.cpp ├── screen.h ├── singleton.h ├── sniffer.cpp ├── sniffer.h ├── tools.cpp ├── tools.h ├── trafficstats.cpp └── trafficstats.h /.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | build* 3 | *.kdev* 4 | *.kate* 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 2 | 3 | PROJECT(ddosmon) 4 | 5 | IF(NOT CMAKE_BUILD_TYPE) 6 | SET(CMAKE_BUILD_TYPE Debug) 7 | ENDIF(NOT CMAKE_BUILD_TYPE) 8 | 9 | FIND_PACKAGE(Boost COMPONENTS thread system REQUIRED) 10 | INCLUDE_DIRECTORIES(/usr/include/libxml2 /usr/include/lua5.1) 11 | ADD_DEFINITIONS(-D_REENTRANT) 12 | 13 | SET(CMAKE_CXX_FLAGS_DEBUG "-O1 -g -ggdb -fno-inline ") 14 | SET(CMAKE_CXX_FLAGS_RELEASE "-O2 -rdynamic") 15 | SET(CMAKE_CXX_FLAGS "-Wall -fmessage-length=0 -include ${PROJECT_SOURCE_DIR}/src/headers.h") 16 | 17 | ADD_EXECUTABLE(ddosmon 18 | src/configmanager.cpp src/ipswitcher.h src/screen.cpp 19 | src/configmanager.h src/logger.cpp src/screen.h 20 | src/ddos.cpp src/logger.h src/singleton.h 21 | src/ddos.h src/monitor.cpp src/sniffer.cpp 22 | src/ddosmon.cpp src/monitor.h src/sniffer.h 23 | src/dispatcher.cpp src/packet.cpp src/tools.cpp 24 | src/dispatcher.h src/packet.h src/tools.h 25 | src/headers.h src/scheduler.cpp src/trafficstats.cpp 26 | src/ipswitcher.cpp src/scheduler.h src/trafficstats.h 27 | ) 28 | 29 | TARGET_LINK_LIBRARIES(ddosmon ${Boost_LIBRARIES} lua5.1 xml2 ncurses) 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### DDOS Monitor 2 | 3 | ![ScreenShot](https://raw.github.com/edubart/ddosmon/master/screenshot.png) 4 | 5 | Program that uses low level linux packet sniffing in incoming network traffic 6 | for monitoring possible network attacks and reacting to them by alerting and 7 | triggering user defined self defence mechanisms. 8 | 9 | With a ncurses interface you can monitor network traffic live and watch 10 | recent events. Logs are saved to log folder, any ddos attack detection send 11 | an email to the user. 12 | 13 | It can classify following attacks: 14 | * SYN Flood 15 | * UDP Flood 16 | * ICMP Flood 17 | 18 | Any other attack with massive amount of traffic or packet would still be detected. 19 | 20 | ### Building 21 | 22 | ``` 23 | git clone git@github.com:edubart/ddosmon ddosmon 24 | cd ddosmon 25 | mkdir build && cd build 26 | cmake .. 27 | make 28 | ``` 29 | 30 | ### Running 31 | 32 | ``` 33 | # optional, I usually run this inside a screen session 34 | screen 35 | 36 | sudo ./build/ddosmon configs/example.lua 37 | ``` 38 | 39 | **NOTE:** Root is needed for sniffing the network adapter packets. 40 | 41 | 42 | ### Scripts 43 | 44 | Script called when a known DDOS attack starts or stops: 45 | `./scripts/networkcompromise ` 46 | 47 | Script called to notificate admins (usually via email): 48 | `./scripts/notificate ` 49 | 50 | Script called when one of your servers ip address might be unreachable and you may want to block/unblock it from your main server: 51 | `./scripts/ipblock ` 52 | 53 | ### Configurations 54 | 55 | You can find and edit these configuration for you needs inside `configs/home.lua` 56 | 57 | * interface = "eth0" 58 | * global_traffic_threshold = 900000 59 | * global_packets_threshold = 225000 60 | * ip_traffic_threshold = 500000 61 | * ip_packets_threshold = 125000 62 | * notification_traffic_threshold = 20000 63 | * notification_packets_threshold = 20000 64 | * ipblock_retry_ticks = 5*3600*1000 65 | * notification_command = "./scripts/notificate \"%1%\" \"%2%\" &" 66 | * onblockip_command = "./scripts/ipblock block %1% &" 67 | * onunblockip_command = "./scripts/ipblock unblock %1% &" 68 | * network_uncompromise_ticks = 30 69 | * onnetwork_compromise_command = "./scripts/networkcompromise compromised &" 70 | * onnetwork_uncompromise_command = "./scripts/networkcompromise uncompromised &" 71 | * log="logs/home.log" 72 | * watchedips="configs/example_watchedips.xml" 73 | * notificationsubject="DDOS Monitor on server1 notification" 74 | 75 | ### Watched IPs 76 | 77 | **NOTE:** Don't foger to configure the ips you want to monitor in the `example_watchedips.xml` file. 78 | 79 | This program was intended to monitor multiple ip addresses, so you can configure as many you like. 80 | -------------------------------------------------------------------------------- /configs/example.lua: -------------------------------------------------------------------------------- 1 | interface = "eth0" 2 | global_traffic_threshold = 900000 3 | global_packets_threshold = 30 4 | ip_traffic_threshold = 500000 5 | ip_packets_threshold = 125000 6 | notification_traffic_threshold = 20000 7 | notification_packets_threshold = 30 8 | ipblock_retry_ticks = 5*3600*1000 9 | notification_command = "./scripts/notificate \"%1%\" \"%2%\" &" 10 | onblockip_command = "./scripts/ipblock block %1% &" 11 | onunblockip_command = "./scripts/ipblock unblock %1% &" 12 | network_uncompromise_ticks = 30 13 | onnetwork_compromise_command = "./scripts/networkcompromise compromised &" 14 | onnetwork_uncompromise_command = "./scripts/networkcompromise uncompromised &" 15 | log="logs/example.log" 16 | watchedips="configs/example_watchedips.xml" 17 | notificationsubject="DDOS Monitor on server1 notification" 18 | -------------------------------------------------------------------------------- /configs/example_watchedips.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/edubart/ddosmon/3157164a93acf7a4f12fb7d62aeb6ed1b378a998/screenshot.png -------------------------------------------------------------------------------- /scripts/ipblock: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # shutdowns an ip and notify servers 3 | # by bart :) 4 | 5 | # configurations 6 | MYSQL_HOST="localhost" 7 | MYSQL_PORT="3306" 8 | MYSQL_USER="root" 9 | MYSQL_PASSWORD="" 10 | MYSQL_DATABASE="login" 11 | WATCHEDIPS_XML="configs/*.xml" 12 | 13 | if [ -z $1 ] || [ -z $2 ]; then 14 | echo "Usage: ${0} " 15 | exit 16 | fi 17 | 18 | IPSTR=$2 19 | IPSTR2=`echo ${IPSTR//./ } | awk '{ print $4" "$3" "$2" "$1}'` 20 | let IP="0x`printf '%02X' ${IPSTR2}; echo`" 21 | INTERFACE=`cat $WATCHEDIPS_XML | grep $IPSTR | sed 's/.*interface="\([^"]*\)".*/\1/'` 22 | MYSQL_COMMAND="mysql --host=${MYSQL_HOST} --port=${MYSQL_PORT} --user=${MYSQL_USER} --password=${MYSQL_PASSWORD} ${MYSQL_DATABASE}" 23 | 24 | if [ -z $INTERFACE ]; then 25 | echo "Ip not found on watchedips.xml" 26 | exit 27 | fi 28 | 29 | executeQuery() { 30 | echo $1 | ${MYSQL_COMMAND} 31 | } 32 | 33 | blockip() { 34 | executeQuery "INSERT INTO blocked_server_ips (ip) VALUES ('${1}')" 35 | #ifconfig ${INTERFACE} ${IPSTR} down 36 | } 37 | 38 | unblockip() { 39 | executeQuery "DELETE FROM blocked_server_ips WHERE ip='${1}'" 40 | #ifconfig ${INTERFACE} ${IPSTR} up 41 | } 42 | 43 | if [ $1 = "block" ]; then 44 | blockip `echo ${IP}` 45 | elif [ $1 = "unblock" ]; then 46 | unblockip `echo ${IP}` 47 | else 48 | echo "invalid option" 49 | fi 50 | -------------------------------------------------------------------------------- /scripts/networkcompromise: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z $1 ]; then 4 | echo "Usage: ${0} " 5 | exit 6 | fi 7 | 8 | sendSignalToServer() { 9 | #inform any server that it is being attacked here 10 | } 11 | 12 | if [ $1 = "compromised" ]; then 13 | sendSignalToServer SIGUSR1 14 | elif [ $1 = "uncompromised" ]; then 15 | sendSignalToServer SIGUSR2 16 | else 17 | echo "invalid option" 18 | fi 19 | -------------------------------------------------------------------------------- /scripts/notificate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SUBJECT=$1 4 | MESSAGE=$2 5 | NOTIFY_EMAILS="example@gmail.com" 6 | 7 | echo "$MESSAGE" | mail -s "$SUBJECT" $NOTIFY_EMAILS 8 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | Makefile 3 | headers.h.gch 4 | CMakeFiles 5 | build 6 | qtcreator-build 7 | cmake_install.cmake 8 | CMakeCache.txt 9 | *.o 10 | ddosmon 11 | !.gitignore 12 | -------------------------------------------------------------------------------- /src/configmanager.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "configmanager.h" 3 | 4 | ConfigManager::ConfigManager() : m_isLoaded(false) 5 | { 6 | } 7 | 8 | ConfigManager::~ConfigManager() 9 | { 10 | 11 | } 12 | 13 | void ConfigManager::loadFile() 14 | { 15 | lua_State* luaHandle = lua_open(); 16 | 17 | if(!luaHandle) { 18 | LOG_FATAL("Could not create lua handle."); 19 | } 20 | 21 | if(luaL_dofile(luaHandle, m_confString[CONFIG_FILE].c_str())) { 22 | lua_close(luaHandle); 23 | LOG_FATAL("Could not load " << m_confString[CONFIG_FILE]); 24 | } 25 | 26 | m_confString[INTERFACE] = getGlobalString(luaHandle, "interface","eth0"); 27 | m_confString[LOG_FILE] = getGlobalString(luaHandle, "log","ddosmon.log"); 28 | m_confString[WATCHEDIPS_XML] = getGlobalString(luaHandle, "watchedips","watchedips.xml"); 29 | m_confString[NOTIFICATION_COMMAND] = getGlobalString(luaHandle, "notification_command",""); 30 | m_confString[ONBLOCKIP_COMMAND] = getGlobalString(luaHandle, "onblockip_command",""); 31 | m_confString[ONUNBLOCKIP_COMMAND] = getGlobalString(luaHandle, "onunblockip_command", ""); 32 | m_confString[ONNETWORK_COMPROMISE_COMMAND] = getGlobalString(luaHandle, "onnetwork_compromise_command",""); 33 | m_confString[ONNETWORK_UNCOMPROMISE_COMMAND] = getGlobalString(luaHandle, "onnetwork_uncompromise_command", ""); 34 | m_confString[NOTIFICATION_SUBJECT] = getGlobalString(luaHandle, "notificationsubject", "DDOS Monitor notification"); 35 | m_confInteger[NOTIFICATION_TRAFFIC_THRESHOLD] = getGlobalNumber(luaHandle, "notification_traffic_threshold", 20000); 36 | m_confInteger[NOTIFICATION_PACKETS_THRESHOLD] = getGlobalNumber(luaHandle, "notification_packets_threshold", 15000); 37 | m_confInteger[IP_TRAFFIC_THRESHOLD] = getGlobalNumber(luaHandle, "ip_traffic_threshold", 500000); 38 | m_confInteger[IP_PACKETS_THRESHOLD] = getGlobalNumber(luaHandle, "ip_packets_threshold", 125000); 39 | m_confInteger[GLOBAL_TRAFFIC_THRESHOLD] = getGlobalNumber(luaHandle, "global_traffic_threshold", 500000); 40 | m_confInteger[GLOBAL_PACKETS_THRESHOLD] = getGlobalNumber(luaHandle, "global_packets_threshold", 125000); 41 | m_confInteger[IPBLOCK_RETRY_TICKS] = getGlobalNumber(luaHandle, "ipblock_retry_ticks", 14400000); 42 | m_confInteger[NETWORK_UNCOMPROMISE_TICKS] = getGlobalNumber(luaHandle, "network_uncompromise_ticks", 30); 43 | m_isLoaded = true; 44 | 45 | lua_close(luaHandle); 46 | } 47 | 48 | const std::string& ConfigManager::getString(uint32_t _what) const 49 | { 50 | if(m_isLoaded && _what < LAST_STRING_CONFIG) 51 | return m_confString[_what]; 52 | else { 53 | LOG_WARN("Failed to read the configuration" << _what); 54 | static std::string dummyStr = ""; 55 | return dummyStr; 56 | } 57 | } 58 | 59 | int64_t ConfigManager::getNumber(uint32_t _what) const 60 | { 61 | if(m_isLoaded && _what < LAST_INTEGER_CONFIG) 62 | return m_confInteger[_what]; 63 | else { 64 | LOG_WARN("Failed to read the configuration" << _what); 65 | return 0; 66 | } 67 | } 68 | 69 | bool ConfigManager::setNumber(uint32_t _what, int64_t _value) 70 | { 71 | if(_what < LAST_INTEGER_CONFIG) { 72 | m_confInteger[_what] = _value; 73 | return true; 74 | } else { 75 | LOG_WARN("Failed to write the configuration" << _what); 76 | return false; 77 | } 78 | } 79 | 80 | bool ConfigManager::setString(uint32_t _what, const std::string& _value) 81 | { 82 | if(_what < LAST_STRING_CONFIG) { 83 | m_confString[_what] = _value; 84 | return true; 85 | } else { 86 | LOG_WARN("Failed to write the configuration" << _what); 87 | return false; 88 | } 89 | } 90 | 91 | std::string ConfigManager::getGlobalString(lua_State* _luaHandle, const std::string& _identifier, const std::string& _default) 92 | { 93 | lua_getglobal(_luaHandle, _identifier.c_str()); 94 | 95 | if(!lua_isstring(_luaHandle, -1)) { 96 | lua_pop(_luaHandle, 1); 97 | return _default; 98 | } 99 | 100 | int len = (int)lua_strlen(_luaHandle, -1); 101 | std::string ret(lua_tostring(_luaHandle, -1), len); 102 | lua_pop(_luaHandle,1); 103 | 104 | return ret; 105 | } 106 | 107 | int64_t ConfigManager::getGlobalNumber(lua_State* _luaHandle, const std::string& _identifier, int64_t _default) 108 | { 109 | lua_getglobal(_luaHandle, _identifier.c_str()); 110 | 111 | if(!lua_isnumber(_luaHandle, -1)) { 112 | lua_pop(_luaHandle, 1); 113 | return _default; 114 | } 115 | 116 | int64_t val = (int64_t)lua_tonumber(_luaHandle, -1); 117 | lua_pop(_luaHandle,1); 118 | 119 | return val; 120 | } 121 | 122 | bool ConfigManager::getGlobalBoolean(lua_State* _luaHandle, const std::string& _identifier, bool _default) 123 | { 124 | lua_getglobal(_luaHandle, _identifier.c_str()); 125 | 126 | if(lua_isnumber(_luaHandle, -1)) { 127 | int val = (int)lua_tonumber(_luaHandle, -1); 128 | lua_pop(_luaHandle, 1); 129 | return val != 0; 130 | } else if(lua_isstring(_luaHandle, -1)) { 131 | std::string val = lua_tostring(_luaHandle, -1); 132 | lua_pop(_luaHandle, 1); 133 | return val == "yes"; 134 | } else if(lua_isboolean(_luaHandle, -1)) { 135 | bool v = lua_toboolean(_luaHandle, -1) != 0; 136 | lua_pop(_luaHandle, 1); 137 | return v; 138 | } 139 | 140 | return _default; 141 | } 142 | -------------------------------------------------------------------------------- /src/configmanager.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIGMANAGER_H__ 2 | #define __CONFIGMANAGER_H__ 3 | 4 | #include "headers.h" 5 | 6 | class ConfigManager : public Singleton 7 | { 8 | public: 9 | ConfigManager(); 10 | virtual ~ConfigManager(); 11 | 12 | enum string_config_t { 13 | CONFIG_FILE, 14 | INTERFACE, 15 | LOG_FILE, 16 | ONBLOCKIP_COMMAND, 17 | ONUNBLOCKIP_COMMAND, 18 | ONNETWORK_COMPROMISE_COMMAND, 19 | ONNETWORK_UNCOMPROMISE_COMMAND, 20 | NOTIFICATION_COMMAND, 21 | WATCHEDIPS_XML, 22 | NOTIFICATION_SUBJECT, 23 | LAST_STRING_CONFIG 24 | }; 25 | 26 | enum integer_config_t { 27 | GLOBAL_TRAFFIC_THRESHOLD, 28 | GLOBAL_PACKETS_THRESHOLD, 29 | IP_TRAFFIC_THRESHOLD, 30 | IP_PACKETS_THRESHOLD, 31 | NOTIFICATION_TRAFFIC_THRESHOLD, 32 | NOTIFICATION_PACKETS_THRESHOLD, 33 | IPBLOCK_RETRY_TICKS, 34 | NETWORK_UNCOMPROMISE_TICKS, 35 | LAST_INTEGER_CONFIG 36 | }; 37 | 38 | void loadFile(); 39 | const std::string& getString(uint32_t _what) const; 40 | int64_t getNumber(uint32_t _what) const; 41 | bool setNumber(uint32_t _what, int64_t _value); 42 | bool setString(uint32_t _what, const std::string& _value); 43 | 44 | private: 45 | std::string getGlobalString(lua_State* _luaHandle, const std::string& _identifier, const std::string& _default=""); 46 | int64_t getGlobalNumber(lua_State* _luaHandle, const std::string& _identifier, int64_t _default=0); 47 | bool getGlobalBoolean(lua_State* _luaHandle, const std::string& _identifier, bool _default=false); 48 | 49 | bool m_isLoaded; 50 | std::string m_confString[LAST_STRING_CONFIG]; 51 | int64_t m_confInteger[LAST_INTEGER_CONFIG]; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/ddos.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "ddos.h" 3 | #include "screen.h" 4 | #include "configmanager.h" 5 | #include "ipswitcher.h" 6 | #include "trafficstats.h" 7 | 8 | #define DDOS_CONFIRM_SECONDS 5 9 | 10 | Ddos::Ddos(uint32_t ip) : 11 | m_ip(ip), 12 | m_startedTime(getSystemTime()), 13 | m_duration(0), 14 | m_totalBytes(0), 15 | m_activeTicks(0), 16 | m_stopTicks(0), 17 | m_state(ACTIVE_NOT_CONFIRMED), 18 | m_offlined(false) 19 | { 20 | m_ddosType = "not detected"; 21 | } 22 | 23 | Ddos::~Ddos() 24 | { 25 | } 26 | 27 | 28 | void Ddos::update(TrafficStats *trafficStats) 29 | { 30 | uint32_t kbits = trafficStats->getKBits(); 31 | uint32_t packets = trafficStats->getPackets(); 32 | 33 | m_duration++; 34 | m_totalBytes += trafficStats->getBytes(); 35 | 36 | // force ip offline when threshold > allowed threshold 37 | if(!m_offlined && (kbits >= ConfigManager::instance()->getNumber(ConfigManager::IP_TRAFFIC_THRESHOLD) || 38 | packets >= ConfigManager::instance()->getNumber(ConfigManager::IP_PACKETS_THRESHOLD))) { 39 | if(m_state == ACTIVE_NOT_CONFIRMED) { 40 | m_state = ACTIVE_CONFIRMED; 41 | Screen::instance()->notificate(boost::str(boost::format("DDoS at %1% instantanealy confirmed with %2% kbits/s, possible type: %3%") 42 | % ipToString(m_ip) 43 | % kbits 44 | % trafficStats->getPossibleFloodType()), true); 45 | } 46 | 47 | Screen::instance()->notificate( 48 | boost::str(boost::format("Not allowed threshold at %1% (%2% kbits/s) ip offline forced") 49 | % ipToString(m_ip) % kbits)); 50 | IpSwitcher::instance()->blockIp(m_ip); 51 | m_offlined = true; 52 | } 53 | 54 | // active/stop algorithm 55 | if(kbits >= ConfigManager::instance()->getNumber(ConfigManager::NOTIFICATION_TRAFFIC_THRESHOLD) || 56 | packets >= ConfigManager::instance()->getNumber(ConfigManager::NOTIFICATION_PACKETS_THRESHOLD)) { 57 | m_stopTicks = 0; 58 | 59 | if(m_state == ACTIVE_NOT_CONFIRMED && ++m_activeTicks >= DDOS_CONFIRM_SECONDS) { 60 | m_state = ACTIVE_CONFIRMED; 61 | Screen::instance()->notificate(boost::str(boost::format("DDoS at %1% confirmed with %2% kbits/s, possible type: %3%") 62 | % ipToString(m_ip) 63 | % kbits 64 | % trafficStats->getPossibleFloodType()), true); 65 | } else { 66 | m_ddosType = trafficStats->getPossibleFloodType(); 67 | } 68 | } else { 69 | m_activeTicks = 0; 70 | if(++m_stopTicks >= DDOS_CONFIRM_SECONDS) { 71 | if(m_state == ACTIVE_CONFIRMED) { 72 | Screen::instance()->notificate(boost::str(boost::format("DDoS at %1% stopped") % ipToString(m_ip))); 73 | } else { 74 | Screen::instance()->notificate(boost::str(boost::format("False DDoS alarm at %1%") % ipToString(m_ip))); 75 | } 76 | m_state = STOPED; 77 | } 78 | } 79 | } 80 | 81 | 82 | void Ddos::render() 83 | { 84 | if(m_state != STOPED) { 85 | if(m_state == ACTIVE_CONFIRMED) { 86 | printw(" Active "); 87 | } else { 88 | printw(" Possible "); 89 | } 90 | 91 | printw(boost::str(boost::format 92 | ("DDOS at %1% during %2% seconds with %3% kbits/s, possible type: %4%\n") % 93 | ipToString(m_ip) % m_duration % bytesToKBits(m_totalBytes/m_duration) 94 | % m_ddosType).c_str()); 95 | } else { 96 | printw(boost::str(boost::format 97 | (" %1% At %2% during %3% seconds with %4% kbits/s, possible type: %5%") % 98 | unixTimeToTimeString(m_startedTime/1000) % ipToString(m_ip) % 99 | (m_duration - 5) % bytesToKBits(m_totalBytes/(m_duration-5)) 100 | % m_ddosType).c_str()); 101 | 102 | if(m_offlined) { 103 | printw(" (offlined)"); 104 | } 105 | 106 | printw("\n"); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/ddos.h: -------------------------------------------------------------------------------- 1 | #ifndef DDOS_H 2 | #define DDOS_H 3 | 4 | #include "headers.h" 5 | 6 | class TrafficStats; 7 | 8 | class Ddos 9 | { 10 | public: 11 | enum DdosState { 12 | ACTIVE_NOT_CONFIRMED, 13 | ACTIVE_CONFIRMED, 14 | STOPED 15 | }; 16 | 17 | Ddos(uint32_t ip); 18 | ~Ddos(); 19 | 20 | void update(TrafficStats *trafficStats); 21 | void render(); 22 | 23 | void setState(DdosState state) { m_state = state; } 24 | DdosState getState() const { return m_state; } 25 | 26 | uint32_t getIp() const { return m_ip; } 27 | uint32_t getKBitsTraffic() const { return (((m_totalBytes/m_duration)*8)/1000); } 28 | 29 | private: 30 | uint32_t m_ip; 31 | uint64_t m_startedTime; 32 | uint32_t m_duration; 33 | uint32_t m_totalBytes; 34 | uint32_t m_activeTicks; 35 | uint16_t m_stopTicks; 36 | std::string m_ddosType; 37 | DdosState m_state; 38 | bool m_offlined; 39 | }; 40 | 41 | #endif // DDOS_H 42 | -------------------------------------------------------------------------------- /src/ddosmon.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "sniffer.h" 3 | #include "monitor.h" 4 | #include "dispatcher.h" 5 | #include "scheduler.h" 6 | #include "configmanager.h" 7 | #include "screen.h" 8 | 9 | void signalHandler(int sig) 10 | { 11 | if(sig == SIGINT) 12 | std::cout << std::endl; 13 | LOG_WARN("got signal = " << strsignal(sig)); 14 | 15 | static bool stopSent = false; 16 | if(!stopSent) { 17 | stopSent = true; 18 | Monitor::instance()->stop(); 19 | } 20 | } 21 | 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | // setup the logger 26 | signal(SIGTERM, &signalHandler); 27 | signal(SIGINT, &signalHandler); 28 | signal(SIGHUP, &signalHandler); 29 | signal(SIGKILL, &signalHandler); 30 | 31 | if(argc != 2) { 32 | std::cout << "Usage: " << argv[0] << " " << std::endl; 33 | return -1; 34 | } 35 | 36 | // setup confs 37 | ConfigManager::instance()->setString(ConfigManager::CONFIG_FILE, argv[1]); 38 | ConfigManager::instance()->loadFile(); 39 | Logger::instance()->setVerbosity(Logger::DEBUG); 40 | Logger::instance()->setLogFile(ConfigManager::instance()->getString(ConfigManager::LOG_FILE)); 41 | 42 | // read watchedips 43 | Monitor::instance()->loadWatchedIps(ConfigManager::instance()->getString(ConfigManager::WATCHEDIPS_XML)); 44 | 45 | // setup sniffer 46 | Sniffer *sniffer = new Sniffer(); 47 | sniffer->setIface(ConfigManager::instance()->getString(ConfigManager::INTERFACE).c_str()); 48 | sniffer->setReadPacketSize(128); 49 | sniffer->init(); 50 | 51 | // start core threads 52 | Dispatcher::instance()->start(); 53 | Scheduler::instance()->start(); 54 | 55 | // setup screen 56 | Screen::instance()->setupScreen(); 57 | 58 | Monitor::instance()->setupSniffer(sniffer); 59 | Monitor::instance()->run(); 60 | 61 | 62 | Screen::instance()->destroyScreen(); 63 | Scheduler::instance()->stop(); 64 | Dispatcher::instance()->stop(); 65 | 66 | delete sniffer; 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /src/dispatcher.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "dispatcher.h" 3 | 4 | Dispatcher::Dispatcher() : 5 | m_threadState(STATE_TERMINATED), 6 | m_thread(NULL) 7 | { 8 | 9 | } 10 | 11 | Dispatcher::~Dispatcher() 12 | { 13 | if(m_thread) { 14 | delete m_thread; 15 | } 16 | } 17 | 18 | void Dispatcher::start() 19 | { 20 | m_threadState = STATE_RUNNING; 21 | m_thread = new boost::thread(boost::bind(&Dispatcher::dispatcherThread, this)); 22 | } 23 | 24 | void Dispatcher::dispatcherThread() 25 | { 26 | srand(time(NULL)); 27 | 28 | boost::unique_lock taskLockUnique(m_taskLock, boost::defer_lock); 29 | 30 | Task* task; 31 | 32 | bool running = true; 33 | while(running) { 34 | 35 | taskLockUnique.lock(); 36 | 37 | if(m_taskList.empty()) { 38 | m_taskSignal.wait(taskLockUnique); 39 | } 40 | 41 | if(m_threadState != STATE_RUNNING) { 42 | running = false; 43 | } 44 | 45 | if(!m_taskList.empty() && running) { 46 | task = m_taskList.front(); 47 | m_taskList.pop_front(); 48 | } else { 49 | task = NULL; 50 | } 51 | 52 | taskLockUnique.unlock(); 53 | 54 | if(task) { 55 | if(!task->hasExpired()) { 56 | (*task)(); 57 | } 58 | delete task; 59 | } 60 | } 61 | 62 | m_taskLock.lock(); 63 | 64 | flush(); 65 | m_threadState = STATE_TERMINATED; 66 | 67 | m_taskLock.unlock(); 68 | } 69 | 70 | void Dispatcher::addTask(Task* task, bool pushFront /*= false*/) 71 | { 72 | bool doSignal = false; 73 | 74 | m_taskLock.lock(); 75 | 76 | if(m_threadState == STATE_RUNNING) { 77 | doSignal = m_taskList.empty(); 78 | if(pushFront) { 79 | m_taskList.push_front(task); 80 | } else { 81 | m_taskList.push_back(task); 82 | } 83 | } 84 | 85 | m_taskLock.unlock(); 86 | 87 | if(doSignal) { 88 | m_taskSignal.notify_one(); 89 | } 90 | } 91 | 92 | void Dispatcher::flush() 93 | { 94 | while(!m_taskList.empty()) { 95 | Task* task = m_taskList.front(); 96 | m_taskList.pop_front(); 97 | if(!task->hasExpired()) { 98 | (*task)(); 99 | } 100 | delete task; 101 | } 102 | } 103 | 104 | void Dispatcher::stop() 105 | { 106 | m_taskLock.lock(); 107 | m_threadState = STATE_TERMINATING; 108 | m_taskLock.unlock(); 109 | 110 | m_taskSignal.notify_one(); 111 | m_thread->join(); 112 | } 113 | -------------------------------------------------------------------------------- /src/dispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef __DISPATCHER_H__ 2 | #define __DISPATCHER_H__ 3 | 4 | #include "headers.h" 5 | 6 | const int DISPATCHER_TASK_EXPIRATION = 2000; 7 | 8 | class Task 9 | { 10 | public: 11 | Task(uint32_t ms, const boost::function& f) : m_f(f) { 12 | m_expiration = boost::get_system_time() + boost::posix_time::milliseconds(ms); 13 | } 14 | Task(const boost::function& f) 15 | : m_expiration(boost::date_time::not_a_date_time), m_f(f) { } 16 | 17 | ~Task() { } 18 | 19 | void operator()() { 20 | m_f(); 21 | } 22 | 23 | void setDontExpire() { 24 | m_expiration = boost::date_time::not_a_date_time; 25 | } 26 | 27 | bool hasExpired() const { 28 | if(m_expiration == boost::date_time::not_a_date_time) 29 | return false; 30 | return m_expiration < boost::get_system_time(); 31 | } 32 | 33 | protected: 34 | boost::system_time m_expiration; 35 | boost::function m_f; 36 | }; 37 | 38 | inline Task* createTask(boost::function f) { 39 | return new Task(f); 40 | } 41 | 42 | inline Task* createTask(uint32_t expiration, boost::function f) { 43 | return new Task(expiration, f); 44 | } 45 | 46 | class Dispatcher : public Singleton 47 | { 48 | enum DispatcherState { 49 | STATE_RUNNING, 50 | STATE_TERMINATING, 51 | STATE_TERMINATED 52 | }; 53 | 54 | public: 55 | Dispatcher(); 56 | virtual ~Dispatcher(); 57 | 58 | void addTask(Task* task, bool pushFront = false); 59 | 60 | void start(); 61 | void stop(); 62 | 63 | protected: 64 | void flush(); 65 | 66 | void dispatcherThread(); 67 | 68 | DispatcherState m_threadState; 69 | boost::thread* m_thread; 70 | 71 | boost::mutex m_taskLock; 72 | boost::condition_variable m_taskSignal; 73 | 74 | std::list m_taskList; 75 | }; 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/headers.h: -------------------------------------------------------------------------------- 1 | #ifndef __HEADERS_H__ 2 | #define __HEADERS_H__ 3 | 4 | // g++ -D_REENTRANT -I/usr/include/libxml2 -I/usr/include/lua5.1 headers.h 5 | 6 | //linux 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //linux extras 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | //c 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | //std 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | //boost 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | 66 | //libxml 67 | #include 68 | #include 69 | #include 70 | 71 | //lua 72 | extern "C" 73 | { 74 | #include 75 | #include 76 | #include 77 | } 78 | 79 | //local 80 | #include "tools.h" 81 | #include "singleton.h" 82 | #include "logger.h" 83 | 84 | //ncurses 85 | #include 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /src/ipswitcher.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "ipswitcher.h" 3 | #include "monitor.h" 4 | #include "configmanager.h" 5 | #include "scheduler.h" 6 | #include "screen.h" 7 | 8 | #define CHECK_IP_INTERVAL 5*60*1000 9 | 10 | IpSwitcher::IpSwitcher() 11 | { 12 | Scheduler::instance()->addEvent(createSchedulerTask(CHECK_IP_INTERVAL, boost::bind(&IpSwitcher::checkIps, this))); 13 | } 14 | 15 | IpSwitcher::~IpSwitcher() 16 | { 17 | for(BlockedIpsMap::iterator it =m_blockedIps.begin(); it != m_blockedIps.end();++it) { 18 | unblockIp(it->first); 19 | } 20 | } 21 | 22 | void IpSwitcher::unblockIp(uint32_t ip) 23 | { 24 | system(boost::str(boost::format(ConfigManager::instance()->getString(ConfigManager::ONUNBLOCKIP_COMMAND)) % ipToString(ip)).c_str()); 25 | m_blockedIps.erase(ip); 26 | } 27 | 28 | void IpSwitcher::blockIp(uint32_t ip) 29 | { 30 | system(boost::str(boost::format(ConfigManager::instance()->getString(ConfigManager::ONBLOCKIP_COMMAND)) % ipToString(ip)).c_str()); 31 | m_blockedIps[ip] = getSystemTime(); 32 | } 33 | 34 | bool IpSwitcher::isBlocked(uint32_t ip) const 35 | { 36 | return (m_blockedIps.find(ip) != m_blockedIps.end()); 37 | } 38 | 39 | void IpSwitcher::checkIps() 40 | { 41 | if(!m_blockedIps.empty()) { 42 | int64_t timeNow = getSystemTime(); 43 | int retryTime = ConfigManager::instance()->getNumber(ConfigManager::IPBLOCK_RETRY_TICKS); 44 | 45 | BlockedIpsMap mapBackup = m_blockedIps; 46 | for(BlockedIpsMap::iterator it = mapBackup.begin(); it != mapBackup.end(); ++it) { 47 | const uint32_t &ip = (it->first); 48 | const int64_t &timeBlocked = (it->second); 49 | 50 | if(timeNow - timeBlocked >= retryTime) { 51 | unblockIp(ip); 52 | Screen::instance()->notificate(boost::str(boost::format("Ip %1% offlined is back after %2% minutes") 53 | % ipToString(ip) % ((timeNow - timeBlocked)/(60*1000)))); 54 | } 55 | } 56 | } 57 | 58 | Scheduler::instance()->addEvent(createSchedulerTask(CHECK_IP_INTERVAL, boost::bind(&IpSwitcher::checkIps, this))); 59 | } 60 | -------------------------------------------------------------------------------- /src/ipswitcher.h: -------------------------------------------------------------------------------- 1 | #ifndef IPSWITCHER_H 2 | #define IPSWITCHER_H 3 | 4 | #include "headers.h" 5 | 6 | class IpSwitcher : public Singleton 7 | { 8 | typedef std::map BlockedIpsMap; 9 | 10 | public: 11 | IpSwitcher(); 12 | virtual ~IpSwitcher(); 13 | 14 | void unblockIp(uint32_t ip); 15 | void blockIp(uint32_t ip); 16 | bool isBlocked(uint32_t ip) const; 17 | 18 | void checkIps(); 19 | 20 | private: 21 | BlockedIpsMap m_blockedIps; 22 | }; 23 | 24 | #endif // IPSWITCHER_H 25 | -------------------------------------------------------------------------------- /src/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "logger.h" 3 | 4 | Logger Logger::m_instance __attribute__((init_priority(102))); 5 | 6 | Logger::Logger() : m_verbosity(Logger::INFO) 7 | { 8 | 9 | } 10 | 11 | Logger::~Logger() 12 | { 13 | if(m_logFile.is_open()) { 14 | m_logFile.close(); 15 | } 16 | } 17 | 18 | void Logger::setLogFile(std::string const &logFile) 19 | { 20 | m_logMutex.lock(); 21 | 22 | if(m_logFile.is_open()) { 23 | m_logFile.close(); 24 | } 25 | 26 | if(!logFile.empty()) { 27 | bool fileEmpty = true; 28 | 29 | std::ifstream file; 30 | file.open(logFile.c_str()); 31 | if(file.is_open()) { 32 | file.seekg(0, std::ios_base::end); 33 | if(file.tellg() > 1) { 34 | fileEmpty = false; 35 | } 36 | file.close(); 37 | } 38 | 39 | m_logFile.open(logFile.c_str(), std::ios::out | std::ios::app); 40 | 41 | if(!m_logFile.good()) { 42 | std::cout << "FATAL LOGGER ERROR: Unable to open " + logFile + " for writing!" << std::endl; 43 | 44 | m_logMutex.unlock(); 45 | exit(-1); 46 | } else if(!fileEmpty) { 47 | m_logFile << std::endl << std::endl; 48 | m_logFile.flush(); 49 | } 50 | 51 | } 52 | 53 | m_logMutex.unlock(); 54 | } 55 | 56 | void Logger::output(const std::string& msg, Level verbosity) 57 | { 58 | m_logMutex.lock(); 59 | 60 | static char const *prefixes[] = { "FATAL ERROR: ", "ERROR: ", "WARNING: ", "", "", "", "" }; 61 | static char const *colors[] = { "\033[01;31m ", "\033[01;31m", "\033[01;33m", "\033[0;32m", "\033[1;32m", "\033[01;34m" }; 62 | 63 | if(m_verbosity >= verbosity) { 64 | if(m_logFile.is_open()) { 65 | time_t rawtime; 66 | struct tm* timeinfo; 67 | 68 | time(&rawtime); 69 | timeinfo = localtime(&rawtime); 70 | 71 | m_logFile << std::setw(2) << std::setfill('0') << timeinfo->tm_mday 72 | << "/" << std::setw(2) << std::setfill('0') << timeinfo->tm_mon 73 | << " " << std::setw(2) << std::setfill('0') << timeinfo->tm_hour 74 | << ":" << std::setw(2) << std::setfill('0') << timeinfo->tm_min 75 | << ":" << std::setw(2) << std::setfill('0') << timeinfo->tm_sec 76 | << " "; 77 | 78 | m_logFile << prefixes[verbosity] << msg; 79 | m_logFile.flush(); 80 | } 81 | 82 | if(verbosity != INFO2) { 83 | std::cout << colors[verbosity] << prefixes[verbosity] << msg << "\033[0m" << std::flush; 84 | } 85 | } 86 | 87 | m_logMutex.unlock(); 88 | 89 | if(verbosity == FATAL) { 90 | exit(-1); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOGGER_H__ 2 | #define __LOGGER_H__ 3 | 4 | #include "headers.h" 5 | 6 | class Logger 7 | { 8 | public: 9 | enum Level { 10 | FATAL = 0, 11 | ERROR, 12 | WARN, 13 | INFO, 14 | INFO2, 15 | DEBUG 16 | }; 17 | 18 | Logger(); 19 | ~Logger(); 20 | 21 | void setLogFile(const std::string &logFile); 22 | void setVerbosity(Level verbosity) { m_verbosity = verbosity; } 23 | 24 | bool isLogFileSet() const { return m_logFile.is_open(); } 25 | 26 | void output(std::string const &msg, Level verbosity); 27 | 28 | static Logger* instance() { 29 | return &m_instance; 30 | } 31 | 32 | private: 33 | Level m_verbosity; 34 | 35 | std::ofstream m_logFile; 36 | boost::mutex m_logMutex; 37 | 38 | static Logger m_instance; 39 | }; 40 | 41 | #define _LOG(level, msg) \ 42 | { \ 43 | std::ostringstream os; \ 44 | os << msg << "\n"; \ 45 | Logger::instance()->output(os.str(), Logger::level); \ 46 | } 47 | 48 | #define LOG_INFO(msg) _LOG(INFO, msg) 49 | #define LOG_INFO2(msg) _LOG(INFO2, msg) 50 | #define LOG_DEBUG(msg) _LOG(DEBUG, msg) 51 | #define LOG_WARN(msg) _LOG(WARN, msg) 52 | #define LOG_ERROR(msg) _LOG(ERROR, msg) 53 | #define LOG_FATAL(msg) _LOG(FATAL, msg) 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/monitor.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "monitor.h" 3 | #include "sniffer.h" 4 | #include "packet.h" 5 | #include "scheduler.h" 6 | #include "configmanager.h" 7 | #include "trafficstats.h" 8 | #include "ddos.h" 9 | #include "screen.h" 10 | #include "ipswitcher.h" 11 | 12 | Monitor::Monitor() : 13 | m_sniffer(NULL), 14 | m_running(false), 15 | m_incoming(new TrafficStats(" Incoming")), 16 | m_outgoing(new TrafficStats(" Outgoing")), 17 | m_underMassiveDdos(false) 18 | { 19 | } 20 | 21 | 22 | Monitor::~Monitor() 23 | { 24 | for(WatchedIpList::iterator it = m_watchedIps.begin(); it != m_watchedIps.end(); ++it) { 25 | delete it->second; 26 | } 27 | m_watchedIps.clear(); 28 | 29 | for(DdosList::iterator it = m_ddoses.begin(); it != m_ddoses.end(); ++it) { 30 | delete (*it); 31 | } 32 | m_ddoses.clear(); 33 | 34 | for(DdosList::iterator it = m_oldDdoses.begin(); it != m_oldDdoses.end(); ++it) { 35 | delete (*it); 36 | } 37 | m_oldDdoses.clear(); 38 | 39 | delete m_incoming; 40 | delete m_outgoing; 41 | 42 | if(m_underMassiveDdos) { 43 | system(ConfigManager::instance()->getString(ConfigManager::ONNETWORK_UNCOMPROMISE_COMMAND).c_str()); 44 | } 45 | } 46 | 47 | void Monitor::loadWatchedIps(std::string filename) 48 | { 49 | xmlDocPtr doc = xmlParseFile(filename.c_str()); 50 | 51 | if(doc) { 52 | xmlNodePtr root, p; 53 | std::string tmp; 54 | 55 | root = xmlDocGetRootElement(doc); 56 | if(xmlStrcmp(root->name,(const xmlChar*)"watchedips") != 0) { 57 | xmlFreeDoc(doc); 58 | LOG_FATAL("invalid file format: " << filename); 59 | } 60 | 61 | p = root->children; 62 | 63 | while(p) { 64 | if(xmlStrcmp(p->name, (const xmlChar*)"ip") == 0) { 65 | if(!readXMLString(p, "ip", tmp)) { 66 | LOG_FATAL("missing \'ip\' field in ip node at " << filename); 67 | } 68 | 69 | uint32_t ip = inet_addr(tmp.c_str()); 70 | 71 | if(ip != INADDR_NONE) { 72 | m_watchedIps[ip] = new TrafficStats(tmp); 73 | } else { 74 | LOG_FATAL("invalid ip address " << tmp << " at " << filename); 75 | } 76 | } 77 | 78 | p = p->next; 79 | } 80 | xmlFreeDoc(doc); 81 | } else { 82 | LOG_FATAL("Failed to load watched ips file " << filename); 83 | } 84 | } 85 | 86 | void Monitor::run() 87 | { 88 | Packet packet; 89 | 90 | m_incoming->reset(); 91 | m_outgoing->reset(); 92 | 93 | m_running = true; 94 | 95 | Screen::instance()->render(); 96 | 97 | Scheduler::instance()->addEvent(createSchedulerTask(1000, boost::bind(&Monitor::update, this))); 98 | 99 | while(m_running) { 100 | if(m_sniffer->getNextPacket(&packet)) { 101 | boost::mutex::scoped_lock lockClass(m_monitorMutex); 102 | processPacket(&packet); 103 | } 104 | } 105 | } 106 | 107 | void Monitor::processPacket(Packet *packet) 108 | { 109 | if(packet->type != PACKET_OUTGOING) { 110 | m_incoming->processPacket(packet); 111 | 112 | WatchedIpList::iterator it = m_watchedIps.find(packet->ip->daddr); 113 | if(it != m_watchedIps.end()) { 114 | (it->second)->processPacket(packet); 115 | } 116 | } else { 117 | m_outgoing->processPacket(packet); 118 | } 119 | } 120 | 121 | 122 | void Monitor::stop() 123 | { 124 | m_running = false; 125 | } 126 | 127 | void Monitor::update() 128 | { 129 | boost::mutex::scoped_lock lockClass(m_monitorMutex); 130 | 131 | if(m_running) { 132 | for(WatchedIpList::iterator it = m_watchedIps.begin(); it != m_watchedIps.end(); ++it) { 133 | uint32_t ip = (it->first); 134 | TrafficStats *trafficStats = (it->second); 135 | 136 | Ddos *ddos = NULL; 137 | 138 | // find active ddoses on the watched in 139 | DdosList::iterator it2 = m_ddoses.begin(); 140 | for(; it2 != m_ddoses.end(); ++it2) { 141 | if((*it2)->getState() != Ddos::STOPED && (*it2)->getIp() == ip) { 142 | ddos = (*it2); 143 | break; 144 | } 145 | } 146 | 147 | // create new ddoses 148 | if(!ddos && (trafficStats->getKBits() >= ConfigManager::instance()->getNumber(ConfigManager::NOTIFICATION_TRAFFIC_THRESHOLD) || 149 | trafficStats->getPackets() >= ConfigManager::instance()->getNumber(ConfigManager::NOTIFICATION_PACKETS_THRESHOLD))) { 150 | ddos = new Ddos(ip); 151 | m_ddoses.push_back(ddos); 152 | Screen::instance()->notificate(boost::str(boost::format("Possible new DDoS at %1% with %2% kbits/s") 153 | % ipToString(ip) 154 | % trafficStats->getKBits())); 155 | } 156 | 157 | // update active ddos 158 | if(ddos) { 159 | trafficStats->logStats(boost::str(boost::format(" Flood incoming to %1%") % ipToString(ip)).c_str()); 160 | 161 | Ddos::DdosState prevState = ddos->getState(); 162 | ddos->update(trafficStats); 163 | 164 | if(ddos->getState() == Ddos::STOPED) { 165 | if(prevState == Ddos::ACTIVE_NOT_CONFIRMED) { 166 | m_ddoses.erase(it2); 167 | delete ddos; 168 | } else { 169 | m_ddoses.erase(it2); 170 | m_oldDdoses.push_front(ddos); 171 | 172 | while(m_oldDdoses.size() > 6) { 173 | delete m_oldDdoses.back(); 174 | m_oldDdoses.pop_back(); 175 | } 176 | } 177 | } 178 | } 179 | } 180 | 181 | if(m_incoming->getKBits() >= ConfigManager::instance()->getNumber(ConfigManager::GLOBAL_TRAFFIC_THRESHOLD) || 182 | m_incoming->getPackets() >= ConfigManager::instance()->getNumber(ConfigManager::GLOBAL_PACKETS_THRESHOLD)) { 183 | if(!m_underMassiveDdos) { 184 | system(ConfigManager::instance()->getString(ConfigManager::ONNETWORK_COMPROMISE_COMMAND).c_str()); 185 | m_underMassiveDdos = true; 186 | Screen::instance()->notificate(boost::str(boost::format("Network traffic is compromised, it is under massive DDOS, possible type: %1%") 187 | % m_incoming->getPossibleFloodType()), true); 188 | } 189 | m_massiveDdosPassTicks = 0; 190 | } else if(m_underMassiveDdos) { 191 | m_massiveDdosPassTicks++; 192 | if(m_massiveDdosPassTicks >= ConfigManager::instance()->getNumber(ConfigManager::NETWORK_UNCOMPROMISE_TICKS)) { 193 | system(ConfigManager::instance()->getString(ConfigManager::ONNETWORK_UNCOMPROMISE_COMMAND).c_str()); 194 | m_underMassiveDdos = false; 195 | Screen::instance()->notificate("Network traffic is uncompromised now, the massive flood stopped"); 196 | } 197 | } 198 | 199 | // render screen 200 | Screen::instance()->render(); 201 | 202 | // reset traffic monitors 203 | m_incoming->reset(); 204 | m_outgoing->reset(); 205 | for(WatchedIpList::iterator it = m_watchedIps.begin(); it != m_watchedIps.end(); ++it) { 206 | (it->second)->reset(); 207 | } 208 | 209 | // unlock and add next event 210 | lockClass.unlock(); 211 | Scheduler::instance()->addEvent(createSchedulerTask(1000, boost::bind(&Monitor::update, this))); 212 | } 213 | } 214 | 215 | void Monitor::render() 216 | { 217 | attron(COLOR_PAIR(1)); 218 | printw(" Interface IP Bits In Packets In TCP UDP ICMP SYN\n"); 219 | attroff(COLOR_PAIR(1)); 220 | 221 | m_incoming->render(); 222 | 223 | /* 224 | for(WatchedIpList::iterator it = m_watchedIps.begin(); it != m_watchedIps.end(); ++it) 225 | (it->second)->render(); 226 | */ 227 | 228 | printw("\n"); 229 | 230 | attron(COLOR_PAIR(1)); 231 | printw(" Interface IP Bits Out Packets Out TCP UDP ICMP SYN\n"); 232 | attroff(COLOR_PAIR(1)); 233 | 234 | m_outgoing->render(); 235 | 236 | printw("\n"); 237 | 238 | attron(COLOR_PAIR(1)); 239 | printw(" Current Status\n"); 240 | attroff(COLOR_PAIR(1)); 241 | 242 | if(m_ddoses.size() == 0) { 243 | printw(" Network is fine =)\n"); 244 | } else { 245 | attron(COLOR_PAIR(2)); 246 | 247 | for(DdosList::iterator it = m_ddoses.begin(); it != m_ddoses.end(); ++it) 248 | (*it)->render(); 249 | 250 | 251 | attroff(COLOR_PAIR(2)); 252 | } 253 | 254 | printw("\n"); 255 | 256 | attron(COLOR_PAIR(1)); 257 | printw(" Lastest DDOSes\n"); 258 | attroff(COLOR_PAIR(1)); 259 | 260 | if(m_oldDdoses.size() == 0) { 261 | printw(" None yet\n"); 262 | } else { 263 | for(DdosList::iterator it = m_oldDdoses.begin(); it != m_oldDdoses.end(); ++it) 264 | (*it)->render(); 265 | } 266 | 267 | printw("\n"); 268 | } 269 | -------------------------------------------------------------------------------- /src/monitor.h: -------------------------------------------------------------------------------- 1 | #ifndef MONITOR_H 2 | #define MONITOR_H 3 | 4 | #include "headers.h" 5 | 6 | struct Packet; 7 | 8 | class Ddos; 9 | class TrafficStats; 10 | class Sniffer; 11 | 12 | class Monitor : public Singleton 13 | { 14 | public: 15 | Monitor(); 16 | virtual ~Monitor(); 17 | 18 | void loadWatchedIps(std::string filename); 19 | 20 | void run(); 21 | void stop(); 22 | void update(); 23 | void render(); 24 | 25 | void setupSniffer(Sniffer *sniffer) { m_sniffer = sniffer; } 26 | int getWatchedIpsCount() const { return (int)m_watchedIps.size(); } 27 | 28 | private: 29 | void processPacket(Packet *packet); 30 | 31 | boost::mutex m_monitorMutex; 32 | Sniffer *m_sniffer; 33 | bool m_running; 34 | TrafficStats *m_incoming; 35 | TrafficStats *m_outgoing; 36 | 37 | typedef std::list DdosList; 38 | DdosList m_ddoses; 39 | DdosList m_oldDdoses; 40 | 41 | typedef std::map WatchedIpList; 42 | WatchedIpList m_watchedIps; 43 | 44 | bool m_underMassiveDdos; 45 | int m_massiveDdosPassTicks; 46 | }; 47 | 48 | #endif // MONITOR_H 49 | -------------------------------------------------------------------------------- /src/packet.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "packet.h" 3 | 4 | bool adjustPacketBuffer(Packet *packet) 5 | { 6 | switch(packet->linktype) { 7 | case LINK_ETHERNET: 8 | case LINK_LOOPBACK: 9 | case LINK_PLIP: 10 | packet->packetbuf = packet->buf + ETH_HLEN; 11 | return true; 12 | case LINK_PPP: 13 | case LINK_SLIP: 14 | case LINK_ISDN_RAWIP: 15 | case LINK_IPIP: 16 | packet->packetbuf = packet->buf; 17 | return true; 18 | case LINK_ISDN_CISCOHDLC: 19 | case LINK_FRAD: 20 | case LINK_DLCI: 21 | packet->packetbuf = packet->buf + 4; 22 | return true; 23 | case LINK_FDDI: 24 | packet->packetbuf = packet->buf + sizeof(struct fddihdr); 25 | return true; 26 | case LINK_VLAN: 27 | packet->packetbuf = packet->buf + 18; 28 | return true; 29 | default: 30 | packet->packetbuf = NULL; 31 | return false; 32 | } 33 | } 34 | 35 | uint16_t getFamilyLinkType(uint16_t family) 36 | { 37 | uint16_t result = 0; 38 | switch (family) { 39 | case ARPHRD_ETHER: 40 | result = LINK_ETHERNET; 41 | break; 42 | case ARPHRD_LOOPBACK: 43 | result = LINK_LOOPBACK; 44 | break; 45 | case ARPHRD_SLIP: 46 | case ARPHRD_CSLIP: 47 | case ARPHRD_SLIP6: 48 | case ARPHRD_CSLIP6: 49 | result = LINK_SLIP; 50 | break; 51 | case ARPHRD_PPP: 52 | result = LINK_PPP; 53 | break; 54 | case ARPHRD_FDDI: 55 | result = LINK_FDDI; 56 | break; 57 | case ARPHRD_IEEE802: 58 | case ARPHRD_IEEE802_TR: 59 | result = LINK_TR; 60 | break; 61 | case ARPHRD_FRAD: 62 | result = LINK_FRAD; 63 | break; 64 | case ARPHRD_DLCI: 65 | result = LINK_DLCI; 66 | break; 67 | case ARPHRD_HDLC: 68 | result = LINK_CISCOHDLC; 69 | break; 70 | case ARPHRD_TUNNEL: 71 | result = LINK_IPIP; 72 | break; 73 | default: 74 | result = LINK_INVALID; 75 | break; 76 | } 77 | return result; 78 | } 79 | -------------------------------------------------------------------------------- /src/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKET_H 2 | #define PACKET_H 3 | 4 | #include "headers.h" 5 | 6 | #define LINK_ETHERNET 1 7 | #define LINK_PPP 2 8 | #define LINK_SLIP 3 9 | #define LINK_PLIP 4 10 | #define LINK_LOOPBACK 5 11 | #define LINK_ISDN_RAWIP 6 12 | #define LINK_ISDN_CISCOHDLC 7 13 | #define LINK_CISCOHDLC 7 14 | #define LINK_FDDI 8 15 | #define LINK_FRAD 9 16 | #define LINK_DLCI 10 17 | #define LINK_TR 11 18 | #define LINK_IPIP 12 19 | #define LINK_VLAN 13 20 | #define LINK_INVALID 0 21 | 22 | #define PACKET_BUFFER_SIZE 16384 23 | 24 | struct Packet 25 | { 26 | union { 27 | struct tcphdr *tcp; 28 | struct udphdr *udp; 29 | } in_ip; 30 | struct iphdr *ip; 31 | uint16_t len; 32 | uint16_t linktype; 33 | uint8_t type; 34 | char buf[PACKET_BUFFER_SIZE]; 35 | char *packetbuf; 36 | }; 37 | 38 | bool adjustPacketBuffer(Packet *packet); 39 | uint16_t getFamilyLinkType(uint16_t family); 40 | 41 | #endif // PACKET_H 42 | -------------------------------------------------------------------------------- /src/scheduler.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "scheduler.h" 3 | 4 | Scheduler::Scheduler() : 5 | m_lastEventId(0), 6 | m_threadState(STATE_TERMINATED), 7 | m_thread(NULL) 8 | { 9 | 10 | } 11 | 12 | Scheduler::~Scheduler() 13 | { 14 | if(m_thread) { 15 | delete m_thread; 16 | } 17 | } 18 | 19 | void Scheduler::start() 20 | { 21 | m_threadState = STATE_RUNNING; 22 | m_thread = new boost::thread(boost::bind(&Scheduler::schedulerThread, this)); 23 | } 24 | 25 | void Scheduler::schedulerThread() 26 | { 27 | srand(time(NULL)); 28 | 29 | Dispatcher *dispatcher = Dispatcher::instance(); 30 | 31 | boost::unique_lock eventLockUnique(m_eventLock, boost::defer_lock); 32 | 33 | while(m_threadState != STATE_TERMINATED) { 34 | SchedulerTask* task = NULL; 35 | bool runTask = false; 36 | bool ret = true; 37 | 38 | eventLockUnique.lock(); 39 | 40 | if(m_eventList.empty()) { 41 | m_eventSignal.wait(eventLockUnique); 42 | } else { 43 | ret = m_eventSignal.timed_wait(eventLockUnique, m_eventList.top()->getCycle()); 44 | } 45 | 46 | if(ret == false && (m_threadState != STATE_TERMINATED)) { 47 | task = m_eventList.top(); 48 | m_eventList.pop(); 49 | 50 | EventIdSet::iterator it = m_eventIds.find(task->getEventId()); 51 | if(it != m_eventIds.end()) { 52 | runTask = true; 53 | m_eventIds.erase(it); 54 | } 55 | } 56 | 57 | eventLockUnique.unlock(); 58 | 59 | if(task) { 60 | if(runTask) { 61 | task->setDontExpire(); 62 | dispatcher->addTask(task); 63 | } else { 64 | delete task; 65 | } 66 | } 67 | } 68 | } 69 | 70 | uint32_t Scheduler::addEvent(SchedulerTask* task) 71 | { 72 | bool do_signal = false; 73 | 74 | m_eventLock.lock(); 75 | 76 | if(Scheduler::m_threadState == Scheduler::STATE_RUNNING) { 77 | if(task->getEventId() == 0) { 78 | if(m_lastEventId >= 0xFFFFFFFF) { 79 | m_lastEventId = 0; 80 | } 81 | task->setEventId(++m_lastEventId); 82 | } 83 | m_eventIds.insert(task->getEventId()); 84 | m_eventList.push(task); 85 | do_signal = (task == m_eventList.top()); 86 | } 87 | 88 | m_eventLock.unlock(); 89 | 90 | if(do_signal) 91 | m_eventSignal.notify_one(); 92 | 93 | return task->getEventId(); 94 | } 95 | 96 | 97 | bool Scheduler::stopEvent(uint32_t eventid) 98 | { 99 | if(eventid == 0) { 100 | return false; 101 | } 102 | 103 | m_eventLock.lock(); 104 | 105 | EventIdSet::iterator it = m_eventIds.find(eventid); 106 | if(it != m_eventIds.end()) { 107 | m_eventIds.erase(it); 108 | m_eventLock.unlock(); 109 | return true; 110 | } else { 111 | m_eventLock.unlock(); 112 | return false; 113 | } 114 | } 115 | 116 | void Scheduler::stop() 117 | { 118 | m_eventLock.lock(); 119 | 120 | m_threadState = Scheduler::STATE_TERMINATED; 121 | 122 | while(!m_eventList.empty()) { 123 | delete m_eventList.top(); 124 | m_eventList.pop(); 125 | } 126 | m_eventIds.clear(); 127 | 128 | m_eventLock.unlock(); 129 | 130 | m_eventSignal.notify_one(); 131 | 132 | m_thread->join(); 133 | } 134 | -------------------------------------------------------------------------------- /src/scheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCHEDULER_H__ 2 | #define __SCHEDULER_H__ 3 | 4 | #include "headers.h" 5 | #include "dispatcher.h" 6 | 7 | #define SCHEDULER_MINTICKS 50 8 | 9 | class SchedulerTask : public Task 10 | { 11 | public: 12 | ~SchedulerTask() { } 13 | 14 | void setEventId(uint32_t eventid) {m_eventid = eventid;} 15 | uint32_t getEventId() const {return m_eventid;} 16 | 17 | boost::system_time getCycle() const {return m_expiration;} 18 | 19 | bool operator<(const SchedulerTask& other) const { 20 | return getCycle() > other.getCycle(); 21 | } 22 | 23 | protected: 24 | SchedulerTask(uint32_t delay, const boost::function& f) : Task(delay, f) { 25 | m_eventid = 0; 26 | } 27 | 28 | uint32_t m_eventid; 29 | 30 | friend SchedulerTask* createSchedulerTask(uint32_t, const boost::function&); 31 | }; 32 | 33 | inline SchedulerTask* createSchedulerTask(uint32_t delay, const boost::function& f) 34 | { 35 | assert(delay != 0); 36 | if(delay < SCHEDULER_MINTICKS) { 37 | delay = SCHEDULER_MINTICKS; 38 | } 39 | return new SchedulerTask(delay, f); 40 | } 41 | 42 | class lessSchedTask : public std::binary_function 43 | { 44 | public: 45 | bool operator()(SchedulerTask*& t1, SchedulerTask*& t2) { 46 | return (*t1) < (*t2); 47 | } 48 | }; 49 | 50 | class Scheduler : public Singleton 51 | { 52 | public: 53 | Scheduler(); 54 | virtual ~Scheduler(); 55 | 56 | uint32_t addEvent(SchedulerTask* task); 57 | bool stopEvent(uint32_t eventId); 58 | 59 | void start(); 60 | void stop(); 61 | 62 | enum SchedulerState { 63 | STATE_RUNNING, 64 | STATE_TERMINATED 65 | }; 66 | 67 | protected: 68 | void schedulerThread(); 69 | 70 | boost::mutex m_eventLock; 71 | boost::condition_variable m_eventSignal; 72 | 73 | uint32_t m_lastEventId; 74 | std::priority_queue, lessSchedTask > m_eventList; 75 | typedef std::set EventIdSet; 76 | EventIdSet m_eventIds; 77 | 78 | SchedulerState m_threadState; 79 | boost::thread* m_thread; 80 | }; 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/screen.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "screen.h" 3 | #include "monitor.h" 4 | #include "configmanager.h" 5 | 6 | Screen::Screen() : m_clearScreen(false) 7 | { 8 | } 9 | 10 | Screen::~Screen() 11 | { 12 | } 13 | 14 | void Screen::setupScreen() 15 | { 16 | initscr(); 17 | 18 | start_color(); 19 | assume_default_colors(COLOR_WHITE, COLOR_BLACK); 20 | init_pair(1, COLOR_YELLOW, COLOR_BLACK); 21 | init_pair(2, COLOR_RED, COLOR_BLACK); 22 | attrset(A_BOLD); 23 | curs_set(0); 24 | } 25 | 26 | void Screen::destroyScreen() 27 | { 28 | endwin(); 29 | } 30 | 31 | //TODO: render only the necessary 32 | void Screen::render() 33 | { 34 | boost::mutex::scoped_lock lockClass(m_screenMutex); 35 | 36 | if(m_clearScreen) { 37 | clear(); 38 | m_clearScreen = false; 39 | } 40 | 41 | move(0, 0); 42 | 43 | printw("\n"); 44 | 45 | Monitor::instance()->render(); 46 | 47 | attron(COLOR_PAIR(1)); 48 | printw(" Lastest Actions\n"); 49 | attroff(COLOR_PAIR(1)); 50 | 51 | if(m_notifications.size() == 0) 52 | printw(" None yet\n"); 53 | else 54 | for(NotificationList::iterator it = m_notifications.begin(); it != m_notifications.end(); ++it) 55 | printw((boost::str(boost::format(" %1%\n") % (*it))).c_str()); 56 | 57 | printw("\n"); 58 | 59 | refresh(); 60 | } 61 | 62 | void Screen::notificate(std::string message, bool sendMail) 63 | { 64 | boost::mutex::scoped_lock lockClass(m_screenMutex); 65 | 66 | LOG_INFO2("NOTIFICATION: " << message); 67 | 68 | if(sendMail) { 69 | system(boost::str( 70 | boost::format(ConfigManager::instance()->getString(ConfigManager::NOTIFICATION_COMMAND)) 71 | % ConfigManager::instance()->getString(ConfigManager::NOTIFICATION_SUBJECT) 72 | % message 73 | ).c_str()); 74 | } 75 | 76 | m_notifications.push_front(boost::str(boost::format("%1% %2%") % getCurrentTimeString() % message)); 77 | while(m_notifications.size() > 6) { 78 | m_notifications.pop_back(); 79 | } 80 | 81 | queueClear(); 82 | } 83 | -------------------------------------------------------------------------------- /src/screen.h: -------------------------------------------------------------------------------- 1 | #ifndef SCREEN_H 2 | #define SCREEN_H 3 | 4 | #include "headers.h" 5 | 6 | class Screen : public Singleton 7 | { 8 | public: 9 | Screen(); 10 | virtual ~Screen(); 11 | 12 | void setupScreen(); 13 | void destroyScreen(); 14 | 15 | void render(); 16 | void notificate(std::string message, bool sendMail = false); 17 | 18 | void queueClear() { m_clearScreen = true; } 19 | 20 | private: 21 | boost::mutex m_screenMutex; 22 | typedef std::list NotificationList; 23 | NotificationList m_notifications; 24 | 25 | bool m_clearScreen; 26 | }; 27 | 28 | #endif // SCREEN_H 29 | -------------------------------------------------------------------------------- /src/singleton.h: -------------------------------------------------------------------------------- 1 | #ifndef __SINGLETON_H__ 2 | #define __SINGLETON_H__ 3 | 4 | template 5 | class Singleton 6 | { 7 | private: 8 | Singleton(const Singleton &); 9 | Singleton& operator=(const Singleton &); 10 | 11 | static T* m_instance; 12 | 13 | protected: 14 | Singleton() { 15 | m_instance = static_cast(this); 16 | } 17 | 18 | public: 19 | virtual ~Singleton() { 20 | m_instance = 0; 21 | } 22 | 23 | static T* instance() { 24 | if(!m_instance) { 25 | m_instance = static_cast(new T); 26 | } 27 | return m_instance; 28 | } 29 | }; 30 | 31 | template 32 | T* Singleton::m_instance = 0; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /src/sniffer.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "sniffer.h" 3 | #include "packet.h" 4 | 5 | Sniffer::Sniffer() : m_rawSocket(-1), m_readPacketSize(16384) 6 | { 7 | strcpy(m_iface, "lo"); 8 | } 9 | 10 | Sniffer::~Sniffer() 11 | { 12 | if(m_rawSocket == -1) { 13 | close(m_rawSocket); 14 | m_rawSocket = -1; 15 | } 16 | } 17 | 18 | void Sniffer::init() 19 | { 20 | m_rawSocket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 21 | if(m_rawSocket == -1) { 22 | LOG_FATAL("Unable to create raw socket, maybe you need to be root?"); 23 | } 24 | } 25 | 26 | void Sniffer::setIface(const char *iface) 27 | { 28 | static char ifaces[24][6] = 29 | { "lo", "eth", "sl", "ppp", "ippp", "plip", "fddi", "dvb", 30 | "pvc", "hdlc", "ipsec", "sbni", "wvlan", "wlan", "sm2", "sm3", 31 | "pent", "lec", "brg", "tun", "tap", "cipcb", "tunl", "vlan"}; 32 | 33 | for(int i = 0; i <= 24 - 1; i++) { 34 | if(strncmp(ifaces[i], iface, strlen(ifaces[i])) == 0) { 35 | strcpy(m_iface, iface); 36 | return; 37 | } 38 | } 39 | 40 | LOG_FATAL("Iface " << iface << " not supported"); 41 | } 42 | 43 | bool Sniffer::getNextPacket(Packet *packet) 44 | { 45 | static socklen_t fromlen = sizeof(struct sockaddr_ll); 46 | struct sockaddr_ll fromaddr; 47 | struct ifreq ifr;; 48 | fd_set set; 49 | struct timeval tv; 50 | int ss; 51 | 52 | FD_ZERO(&set); 53 | FD_SET(m_rawSocket, &set); 54 | 55 | tv.tv_sec = 0; 56 | tv.tv_usec = 50000; 57 | 58 | do { 59 | ss = select(m_rawSocket + 1, &set, 0, 0, &tv); 60 | } while ((ss < 0) && (errno == EINTR)); 61 | 62 | if(FD_ISSET(m_rawSocket, &set)) { 63 | if(recvfrom(m_rawSocket, packet->buf, m_readPacketSize, 0, (struct sockaddr *)&fromaddr, &fromlen) == 0) { 64 | return false; 65 | } 66 | 67 | ifr.ifr_ifindex = fromaddr.sll_ifindex; 68 | ioctl(m_rawSocket, SIOCGIFNAME, &ifr); 69 | 70 | if(strcmp(m_iface, ifr.ifr_name) != 0) { 71 | return false; 72 | } 73 | 74 | if(ntohs(fromaddr.sll_protocol) != ETH_P_IP) { 75 | return false; 76 | } 77 | 78 | packet->type = fromaddr.sll_pkttype; 79 | packet->linktype = getFamilyLinkType(fromaddr.sll_hatype); 80 | 81 | if(!adjustPacketBuffer(packet)) { 82 | return false; 83 | } 84 | 85 | packet->ip = (struct iphdr *) (packet->packetbuf); 86 | packet->len = htons(packet->ip->tot_len) + (uint16_t)std::abs((int)(packet->packetbuf - packet->buf)); 87 | if(packet->ip->protocol == IPPROTO_TCP) { 88 | packet->in_ip.tcp = (struct tcphdr *) ((char *) packet->ip + packet->ip->ihl * 4); 89 | } else if(packet->ip->protocol == IPPROTO_UDP) { 90 | packet->in_ip.udp = (struct udphdr *) ((char *) packet->ip + packet->ip->ihl * 4); 91 | } 92 | return true; 93 | } 94 | return false; 95 | } 96 | 97 | -------------------------------------------------------------------------------- /src/sniffer.h: -------------------------------------------------------------------------------- 1 | #ifndef SNIFFER_H 2 | #define SNIFFER_H 3 | 4 | #include "headers.h" 5 | 6 | struct Packet; 7 | 8 | class Sniffer 9 | { 10 | public: 11 | Sniffer(); 12 | virtual ~Sniffer(); 13 | 14 | void init(); 15 | void setIface(const char *iface); 16 | void setReadPacketSize(uint16_t size) { m_readPacketSize = size; } 17 | 18 | bool getNextPacket(Packet *packet); 19 | 20 | private: 21 | int m_rawSocket; 22 | uint32_t m_readPacketSize; 23 | char m_iface[8]; 24 | }; 25 | 26 | #endif // SNIFFER_H 27 | -------------------------------------------------------------------------------- /src/tools.cpp: -------------------------------------------------------------------------------- 1 | #include "headers.h" 2 | #include "tools.h" 3 | 4 | bool readXMLInteger(xmlNodePtr node, const char* tag, int& value) 5 | { 6 | char* nodeValue = (char*)xmlGetProp(node, (xmlChar*)tag); 7 | if(nodeValue) { 8 | value = atoi(nodeValue); 9 | xmlFree(nodeValue); 10 | return true; 11 | } 12 | 13 | return false; 14 | } 15 | 16 | bool readXMLInteger64(xmlNodePtr node, const char* tag, uint64_t& value) 17 | { 18 | char* nodeValue = (char*)xmlGetProp(node, (xmlChar*)tag); 19 | if(nodeValue) { 20 | value = atoll(nodeValue); 21 | xmlFree(nodeValue); 22 | return true; 23 | } 24 | 25 | return false; 26 | } 27 | 28 | bool readXMLFloat(xmlNodePtr node, const char* tag, float& value) 29 | { 30 | char* nodeValue = (char*)xmlGetProp(node, (xmlChar*)tag); 31 | if(nodeValue) { 32 | value = atof(nodeValue); 33 | xmlFree(nodeValue); 34 | return true; 35 | } 36 | 37 | return false; 38 | } 39 | 40 | bool readXMLString(xmlNodePtr node, const char* tag, std::string& value) 41 | { 42 | char* nodeValue = (char*)xmlGetProp(node, (xmlChar*)tag); 43 | if(nodeValue) { 44 | value = nodeValue; 45 | xmlFree(nodeValue); 46 | return true; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | std::string unixTimeToDateString(time_t unixtime) 53 | { 54 | static const char *year[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; 55 | struct tm *local; 56 | std::stringstream ss; 57 | 58 | local = localtime(&unixtime); 59 | 60 | if(local) { 61 | ss << local->tm_mday << " " << year[local->tm_mon] << " " << (local->tm_year + 1900); 62 | } else { 63 | LOG_ERROR("Time conversion for unixtime " << unixtime << " failed."); 64 | ss << "UNIX time: " << unixtime; 65 | } 66 | 67 | return ss.str(); 68 | } 69 | 70 | std::string unixTimeToTimeString(time_t unixtime) 71 | { 72 | struct tm *local; 73 | std::stringstream ss; 74 | 75 | local = localtime(&unixtime); 76 | 77 | if(local) { 78 | ss << std::setw(2) << std::setfill('0') << local->tm_hour 79 | << ":" << std::setw(2) << std::setfill('0') << local->tm_min 80 | << ":" << std::setw(2) << std::setfill('0') << local->tm_sec; 81 | } else { 82 | LOG_ERROR("Time conversion for unixtime " << unixtime << " failed."); 83 | ss << "UNIX time: " << unixtime; 84 | } 85 | 86 | return ss.str(); 87 | } 88 | 89 | std::string unixTimeToString(time_t unixtime) 90 | { 91 | struct tm *local; 92 | std::stringstream ss; 93 | 94 | local = localtime(&unixtime); 95 | 96 | if(local) { 97 | ss << std::setw(2) << std::setfill('0') << local->tm_mday 98 | << "/" << std::setw(2) << std::setfill('0') << local->tm_mon 99 | << "/" << local->tm_year + 1900 100 | << " " << std::setw(2) << std::setfill('0') << local->tm_hour 101 | << ":" << std::setw(2) << std::setfill('0') << local->tm_min 102 | << ":" << std::setw(2) << std::setfill('0') << local->tm_sec; 103 | } else { 104 | LOG_ERROR("Time conversion for unixtime " << unixtime << " failed."); 105 | ss << "UNIX time: " << unixtime; 106 | } 107 | 108 | return ss.str(); 109 | } 110 | 111 | std::string ipToString(uint32_t ip) 112 | { 113 | std::string ret; 114 | ret = inet_ntoa(*(struct in_addr*)&ip); 115 | return ret; 116 | } 117 | -------------------------------------------------------------------------------- /src/tools.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGER_H 2 | #define LOGGER_H 3 | 4 | #include "headers.h" 5 | 6 | // xml helpers 7 | bool readXMLInteger(xmlNodePtr node, const char* tag, int& value); 8 | bool readXMLInteger64(xmlNodePtr node, const char* tag, uint64_t& value); 9 | bool readXMLFloat(xmlNodePtr node, const char* tag, float& value); 10 | bool readXMLString(xmlNodePtr node, const char* tag, std::string& value); 11 | 12 | // time helpers 13 | inline int64_t getSystemTime() { 14 | struct timeval t; 15 | gettimeofday(&t, NULL); 16 | return ((int64_t)t.tv_sec) * 1000 + (int64_t)(t.tv_usec/1000); 17 | } 18 | 19 | std::string unixTimeToDateString(time_t unixtime); 20 | std::string unixTimeToTimeString(time_t unixtime); 21 | std::string unixTimeToString(time_t unixtime); 22 | 23 | inline std::string getCurrentTimeString() { return unixTimeToTimeString(time(NULL)); } 24 | inline std::string getCurrentDateString() { return unixTimeToDateString(time(NULL)); } 25 | inline std::string getCurrentDateTimeString() { return unixTimeToString(time(NULL)); } 26 | 27 | // net tools 28 | std::string ipToString(uint32_t ip); 29 | 30 | inline uint32_t bytesToKBits(uint32_t bytes) { 31 | return (bytes*8)/1000; 32 | } 33 | 34 | 35 | #endif // LOGGER_H 36 | -------------------------------------------------------------------------------- /src/trafficstats.cpp: -------------------------------------------------------------------------------- 1 | #include "trafficstats.h" 2 | #include "packet.h" 3 | 4 | TrafficStats::TrafficStats(std::string name) : 5 | m_bytes(0), 6 | m_packets(0), 7 | m_udpPackets(0), 8 | m_tcpPackets(0), 9 | m_icmpPackets(0), 10 | m_synPackets(0), 11 | m_name(name) 12 | { 13 | } 14 | 15 | 16 | TrafficStats::~TrafficStats() 17 | { 18 | 19 | } 20 | 21 | void TrafficStats::reset() 22 | { 23 | m_bytes = 0; 24 | m_packets = 0; 25 | m_udpPackets = 0; 26 | m_tcpPackets = 0; 27 | m_icmpPackets = 0; 28 | m_synPackets = 0; 29 | } 30 | 31 | void TrafficStats::processPacket(Packet *packet) 32 | { 33 | m_bytes += packet->len; 34 | m_packets++; 35 | 36 | switch(packet->ip->protocol) { 37 | case IPPROTO_TCP: 38 | m_tcpPackets++; 39 | if(packet->in_ip.tcp->syn) { 40 | m_synPackets++; 41 | } 42 | break; 43 | case IPPROTO_UDP: 44 | m_udpPackets++; 45 | break; 46 | case IPPROTO_ICMP: 47 | m_icmpPackets++; 48 | break; 49 | } 50 | } 51 | 52 | void TrafficStats::logStats(const char *prefix) 53 | { 54 | using namespace std; 55 | LOG_INFO2(prefix << " => " << bytesToKBits(m_bytes) << " kbits/s " 56 | << m_packets << " pkt/s " << " (" 57 | << setprecision(3) << (m_packets > 0 ? ((m_tcpPackets*100)/(float)m_packets) : 0) << "% TCP | " 58 | << setprecision(3) << (m_packets > 0 ? ((m_udpPackets*100)/(float)m_packets) : 0) << "% UDP | " 59 | << setprecision(3) << (m_packets > 0 ? ((m_icmpPackets*100)/(float)m_packets) : 0) << "% ICMP | " 60 | << setprecision(3) << (m_tcpPackets > 0 ? ((m_synPackets*100)/(float)m_tcpPackets) : 0) << "% SYN)"); 61 | } 62 | 63 | 64 | void TrafficStats::render() 65 | { 66 | using namespace std; 67 | stringstream out; 68 | out << setfill(' ') << setw(15) << m_name << " " 69 | << setw(8) << setfill(' ') << bytesToKBits(m_bytes) << " kbits/s" << " " 70 | << setw(8) << setfill(' ') << m_packets << " pkt/s " << " " 71 | << setw(6) << setfill(' ') << setprecision(3) << (m_packets > 0 ? ((m_tcpPackets*100)/(float)m_packets) : 0) << "%" << " " 72 | << setw(6) << setfill(' ') << setprecision(3) << (m_packets > 0 ? ((m_udpPackets*100)/(float)m_packets) : 0) << "%" << " " 73 | << setw(6) << setfill(' ') << setprecision(3) << (m_packets > 0 ? ((m_icmpPackets*100)/(float)m_packets) : 0) << "%" << " " 74 | << setw(6) << setfill(' ') << setprecision(3) << (m_tcpPackets > 0 ? ((m_synPackets*100)/(float)m_tcpPackets) : 0) << "%" << " " 75 | << "\n"; 76 | printw("%s", out.str().c_str()); 77 | } 78 | 79 | 80 | std::string TrafficStats::getPossibleFloodType() const 81 | { 82 | std::string floodType = "not detected"; 83 | std::map sortedList; 84 | sortedList[m_udpPackets] = 1; 85 | sortedList[m_synPackets] = 2; 86 | sortedList[m_icmpPackets] = 3; 87 | sortedList[m_tcpPackets] = 4; 88 | if(sortedList.rbegin()->first > 0) { 89 | switch(sortedList.rbegin()->second) { 90 | case 1: 91 | floodType = "UDP flood"; 92 | break; 93 | case 2: 94 | floodType = "SYN flood"; 95 | break; 96 | case 3: 97 | floodType = "ICMP flood"; 98 | break; 99 | case 4: 100 | floodType = "TCP flood"; 101 | break; 102 | } 103 | } 104 | return floodType; 105 | } 106 | -------------------------------------------------------------------------------- /src/trafficstats.h: -------------------------------------------------------------------------------- 1 | #ifndef TRAFFICSTATS_H 2 | #define TRAFFICSTATS_H 3 | 4 | #include "headers.h" 5 | 6 | struct Packet; 7 | 8 | class TrafficStats 9 | { 10 | public: 11 | TrafficStats(std::string name); 12 | ~TrafficStats(); 13 | 14 | void reset(); 15 | void processPacket(Packet *packet); 16 | 17 | void logStats(const char *prefix); 18 | void render(); 19 | 20 | uint32_t getBytes() const { return m_bytes; } 21 | uint32_t getKBits() const { return ((m_bytes*8)/1000); } 22 | uint32_t getPackets() const { return m_packets; } 23 | std::string getPossibleFloodType() const; 24 | 25 | private: 26 | uint32_t m_bytes; 27 | uint32_t m_packets; 28 | uint32_t m_udpPackets; 29 | uint32_t m_tcpPackets; 30 | uint32_t m_icmpPackets; 31 | uint32_t m_synPackets; 32 | std::string m_name; 33 | }; 34 | 35 | #endif // TRAFFICSTATS_H 36 | --------------------------------------------------------------------------------