diff --git a/.gitignore b/.gitignore index 33a9488..0d18f04 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ example +exec \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 930ff05..6f6a05d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,61 @@ { "files.associations": { - "*.tcc": "cpp" + "*.tcc": "cpp", + "ostream": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "chrono": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "map": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "ratio": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "semaphore": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp" } } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..05054c5 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: g++ build active file", + "command": "/usr/bin/g++", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Task generated by Debugger." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/README.md b/README.md index 7280c62..545db3e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # ipban -Ban an IP in time over UFW \ No newline at end of file +A library for managing IP address bans on UFW systems \ No newline at end of file diff --git a/clonelibs.sh b/clonelibs.sh new file mode 100644 index 0000000..906f05c --- /dev/null +++ b/clonelibs.sh @@ -0,0 +1,5 @@ +rm -rf exec + +wget https://git.bitelex.co/marcelb/exec/archive/v0.1_beta.tar.gz +tar -xvf v0.1_beta.tar.gz +rm v0.1_beta.tar.gz \ No newline at end of file diff --git a/lib/ipban.hpp b/lib/ipban.hpp index 46ab509..fca01ad 100644 --- a/lib/ipban.hpp +++ b/lib/ipban.hpp @@ -6,10 +6,13 @@ #include #include #include +#include #include #include +#include "../exec/lib/exec.hpp" + using namespace std; namespace marcelb { @@ -17,30 +20,79 @@ namespace marcelb { #define BOT_LOOP_TIME 60 // 1 minutes #define BOT_SLEEP_LOOP_TIME 1 // 1 second +/** + * Banovani objekt + * IP adresa i vrijeme banovanja +*/ struct _ban { string ip; time_t _time; }; +/** + * Biblioteka za ban IP adrese kroz UFW vatrozid na određeno vrijeme + * Automatski uklanja zabranu po isteku vremena + * Posjeduje vlastiti DB mehanizam za zaštitu od nepovratnog ban-a +*/ class ipban { mutex io; - time_t ban_duration; // u sekundama + time_t ban_duration; + string db_file; vector<_ban> banned; future unban_bot; bool run_unban_bot = true; // interface možda bude trebao za ban + + /** + * Metoda učitava banovane IP adrese iz baze + */ + void load_db(); + + /** + * Metoda ažurira stanja baze sa stanjima iz memorije + */ + bool update_db(); + /** + * Metoda uklanja ban za proslijeđeni iterator vektora banned i ažurira bazu + */ bool unban(vector<_ban>::iterator ban_itr); + + /** + * Metoda poziva exec i dodaje pravila u UFW vatrozid + */ bool ufw_ban(const string& ip); + + /** + * Metoda poziva exec i uklanja pravilo u UFW vatrozidu + */ bool ufw_unban(const string& ip); public: - ipban(const uint& _duration); // u minutama? + + /** + * Konstruktor, prima zadanu vrijednost trajanja ban-a u minutama + * i putanju datoteke baze podataka + */ + ipban(const uint& _duration, const string& db_file = "ipban.db"); // u minutama? + + /** + * Metoda koja banuje proslijeđenu IP adresu, dodaje je u vector banned, ažurira bazu + * Vraća status operacije + */ bool ban(const string& ip); + + /** + * Destruktor, uklanja sve zabrane. + */ ~ipban(); }; +/** + * Funkcija za mirovanje tijeka, koj miruje do isteka vremena ili logičkog stanja uvijeta + * Prima vrijeme u sekundama, i logički uvijet +*/ static void sleep_if(const uint& _time, const bool& _condition); } diff --git a/src/ipban.cpp b/src/ipban.cpp index 8214869..87c6bc0 100644 --- a/src/ipban.cpp +++ b/src/ipban.cpp @@ -1,23 +1,23 @@ #include "../lib/ipban.hpp" -marcelb::ipban::ipban(const uint& _duration) { +marcelb::ipban::ipban(const uint& _duration, const string& _db_file) { ban_duration = _duration*60; + db_file = _db_file; + load_db(); unban_bot = async(launch::async, [&]() { while (run_unban_bot) { sleep_if(BOT_LOOP_TIME, run_unban_bot); - cout << "Sleep" << endl; - io.lock(); for (uint i=0; i= ban_duration) { - unban(banned.begin() + i); + if (!unban(banned.begin() + i)) { + cout << "[ERROR] Unban is not done properly! " << endl; + } } } - io.unlock(); } return; }); - } marcelb::ipban::~ipban() { @@ -28,27 +28,79 @@ marcelb::ipban::~ipban() { } } +void marcelb::ipban::load_db() { + string line; + ifstream mydb (db_file); + if (mydb.is_open()) { + while (getline(mydb, line) ) { + struct _ban saved_ban; + saved_ban.ip = line.substr(0, line.find('-')); + saved_ban._time = stol(line.substr(line.find('-')+1)); + banned.push_back(saved_ban); + } + mydb.close(); + } +} + +bool marcelb::ipban::update_db() { + bool success = false; + ofstream mydb (db_file); + if (mydb.is_open()) { + for (int i=0; i::iterator ban_itr) { - ufw_unban(ban_itr->ip); + bool status = ufw_unban(ban_itr->ip); io.lock(); banned.erase(ban_itr); + status = status && update_db(); io.unlock(); + return status; } bool marcelb::ipban::ufw_ban(const string& ip) { - cout << "UFW ban IP: " << ip << endl; + string ufw_cmd = "sudo ufw deny from " + ip + " to any"; + try { + string execute_res = exec(ufw_cmd); + if (execute_res == "Rule added\n") { + return true; + } + } catch (const string except) { + cout << except << endl; + } + return false; } bool marcelb::ipban::ufw_unban(const string& ip) { - cout << "UFW unban IP: " << ip << endl; + string ufw_cmd = "sudo ufw delete deny from " + ip + " to any"; + try { + string execute_res = exec(ufw_cmd); + if (execute_res == "Rule deleted\n") { + return true; + } + } catch (const string except) { + cout << except << endl; + } + return false; } static void marcelb::sleep_if(const uint& _time, const bool& _condition) { diff --git a/test/compile.sh b/test/compile.sh new file mode 100644 index 0000000..543a588 --- /dev/null +++ b/test/compile.sh @@ -0,0 +1 @@ +g++ test.cpp ../src/*.cpp ../exec/src/*.cpp -o test \ No newline at end of file diff --git a/test/gen_db.cpp b/test/gen_db.cpp new file mode 100644 index 0000000..b825f75 --- /dev/null +++ b/test/gen_db.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include + +struct _ban { + std::string ip; + long int _time; +}; + +// Funkcija za generiranje pseudoslučajnih IP adresa +std::string generateRandomIP() { + return std::to_string(rand() % 256) + "." + + std::to_string(rand() % 256) + "." + + std::to_string(rand() % 256) + "." + + std::to_string(rand() % 256); +} + +int main() { + //std::ofstream mydb("datoteka.txt"); + + // Postavka generiranja pseudoslučajnih brojeva + srand(static_cast(time(0))); + + // Generiranje desetaka IP adresa i povezanih vremenskih brojeva + for (int i = 0; i < 10; ++i) { + _ban generated_ban; + generated_ban.ip = generateRandomIP(); + generated_ban._time = static_cast(time(nullptr) - rand()%100); + + // Ispisivanje u datoteku + std::cout << generated_ban.ip << "-" << generated_ban._time << std::endl; + } + + std::cout << "Generiranje završeno." << std::endl; + + return 0; +} \ No newline at end of file diff --git a/test/ipban.db b/test/ipban.db new file mode 100644 index 0000000..e150c3a --- /dev/null +++ b/test/ipban.db @@ -0,0 +1 @@ +90.163.88.49-1702323353 diff --git a/test/test b/test/test index 42cc065..885e984 100755 Binary files a/test/test and b/test/test differ diff --git a/test/test.cpp b/test/test.cpp index f5e7fed..7ff08f9 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -2,9 +2,36 @@ using namespace marcelb; +std::string generateRandomIP() { + return std::to_string(rand() % 256) + "." + + std::to_string(rand() % 256) + "." + + std::to_string(rand() % 256) + "." + + std::to_string(rand() % 256); +} + +// time_t random_time (const uint& offset) { +// time_t _time = time(nullptr); +// if (_time %2 == 0) { +// return (time(nullptr) + rand()%offset); +// } +// else { +// return (time(nullptr) - rand()%offset); +// } +// } + int main() { ipban myban(1); - myban.ban("192.168.2.74"); - sleep(80); + // myban.ban("192.168.2.74"); + // sleep(300); + uint i=0; + + while (i<10) { + string ip = generateRandomIP(); + cout << "Ban " << ip << endl; + myban.ban(ip); + sleep(30); + i++; + } + return 0; } \ No newline at end of file