added ip banning

This commit is contained in:
Benedikt Galbavy 2023-11-19 21:49:40 +01:00
parent f66d895326
commit 61c41aefeb
5 changed files with 128 additions and 9 deletions

View File

@ -10,7 +10,7 @@ BUILD_DIR = build
SOURCES_CLIENT = client.cpp SOURCES_CLIENT = client.cpp
OBJS_CLIENT = $(addprefix $(BUILD_DIR)/,$(SOURCES_CLIENT:.cpp=.o)) OBJS_CLIENT = $(addprefix $(BUILD_DIR)/,$(SOURCES_CLIENT:.cpp=.o))
SOURCES_SERVER = server.cpp user.cpp user_handler.cpp mail.cpp SOURCES_SERVER = server.cpp user.cpp user_handler.cpp mail.cpp ip_ban.cpp
OBJS_SERVER = $(addprefix $(BUILD_DIR)/,$(SOURCES_SERVER:.cpp=.o)) OBJS_SERVER = $(addprefix $(BUILD_DIR)/,$(SOURCES_SERVER:.cpp=.o))
all: $(BUILD_DIR) $(TARGET) all: $(BUILD_DIR) $(TARGET)

54
server/ip_ban.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "ip_ban.h"
#include <chrono>
#include <filesystem>
#include <iterator>
#include <fstream>
ip_ban::ip_ban() : m_ban()
{
this->file = fs::path();
}
ip_ban::~ip_ban()
{
if (this->file.empty())
return;
json jsonfile = this->ban_list;
std::ofstream ofs(this->file, std::ofstream::out | std::ofstream::trunc);
ofs << jsonfile.dump();
}
void ip_ban::loadFile(fs::path file)
{
this->file = file;
if (fs::exists(file)) {
std::ifstream ifs(file);
this->ban_list = json::parse(ifs);
}
}
void ip_ban::failedAttempt(std::string username, std::string ip)
{
printf("%s\n", username.c_str());
std::unique_lock<std::shared_mutex> lock(this->m_ban);
std::map<std::string, std::pair<std::map<std::string, ushort>, time_t>>::iterator it = this->ban_list.insert({ip, {{}, 0}}).first;
if (++it->second.first.insert({username, 0}).first->second >= MAX_ATTEMPTS) { // increase attempt count && check if reached MAX_ATTEMPTS
for (auto& pair : it->second.first ) { // reset attempts to 0 for all names
pair.second = 0;
}
(*it).second.second = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) + BAN_TIME; // set unban time to current time + BAN_TIME seconds
}
}
bool ip_ban::checkBanned(std::string ip)
{
std::shared_lock<std::shared_mutex> lock(this->m_ban);
std::map<std::string, std::pair<std::map<std::string, ushort>, time_t>>::iterator it;
return (it = this->ban_list.find(ip)) != this->ban_list.end() && (*it).second.second > std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
}

47
server/ip_ban.h Normal file
View File

@ -0,0 +1,47 @@
#pragma once
#include <filesystem>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <string>
#include <chrono>
#include <nlohmann/json.hpp>
#define BAN_TIME 60
#define MAX_ATTEMPTS 3
namespace fs = std::filesystem;
using json = nlohmann::json;
class ip_ban {
public:
static ip_ban& getInstance() {
static ip_ban instance;
return instance;
};
ip_ban(ip_ban const&) = delete;
ip_ban(ip_ban&&) = delete;
ip_ban& operator=(ip_ban const&) = delete;
ip_ban& operator=(ip_ban &&) = delete;
void loadFile(fs::path file);
void failedAttempt(std::string username, std::string ip);
bool checkBanned(std::string ip);
protected:
ip_ban();
~ip_ban();
std::shared_mutex m_ban;
fs::path file;
std::map<std::string, std::pair<std::map<std::string, ushort>, time_t>> ban_list;
};

View File

@ -1,5 +1,4 @@
#include "mail.h" #include "mail.h"
#include <mutex>
mail::mail(std::string filename, std::string subject, std::string sender) : mail::mail(std::string filename, std::string subject, std::string sender) :
filename(filename), filename(filename),

View File

@ -1,3 +1,4 @@
#include "ip_ban.h"
#include "user.h" #include "user.h"
#include "user_handler.h" #include "user_handler.h"
@ -71,7 +72,7 @@ std::string getSha1(const std::string& p_arg);
void *clientCommunication(void *data); void *clientCommunication(void *data);
void signalHandler(int sig); void signalHandler(int sig);
std::string cmdLOGIN(std::vector<std::string>& received, std::string& loggedInUsername); std::string cmdLOGIN(std::vector<std::string>& received, std::string& loggedInUsername, const std::string& ip);
std::string cmdSEND(std::vector<std::string>& received, const std::string& loggedInUsername); std::string cmdSEND(std::vector<std::string>& received, const std::string& loggedInUsername);
std::string cmdLIST(std::vector<std::string>& received, const std::string& loggedInUsername); std::string cmdLIST(std::vector<std::string>& received, const std::string& loggedInUsername);
std::string cmdREAD(std::vector<std::string>& received, const std::string& loggedInUsername); std::string cmdREAD(std::vector<std::string>& received, const std::string& loggedInUsername);
@ -81,6 +82,13 @@ std::string cmdDEL(std::vector<std::string>& received, const std::string& logged
inline void exiting(); inline void exiting();
inline std::string read_file(std::string_view path); inline std::string read_file(std::string_view path);
struct args
{
int socket;
std::string ip;
fs::path spool_dir;
};
int main (int argc, char* argv[]) int main (int argc, char* argv[])
{ {
if (argc < 3 || if (argc < 3 ||
@ -106,6 +114,8 @@ int main (int argc, char* argv[])
user_handler::getInstance().setSpoolDir(spool_dir); user_handler::getInstance().setSpoolDir(spool_dir);
ip_ban::getInstance().loadFile(spool_dir / "bans.json");
std::atexit(exiting); std::atexit(exiting);
char* p; char* p;
@ -181,7 +191,7 @@ int main (int argc, char* argv[])
ntohs(cliaddress.sin_port)); ntohs(cliaddress.sin_port));
// clientCommunication(&new_socket); // returnValue can be ignored // clientCommunication(&new_socket); // returnValue can be ignored
pthread_t tid; pthread_t tid;
pthread_create(&tid, NULL, clientCommunication, (void *)new int(new_socket)); pthread_create(&tid, NULL, clientCommunication, static_cast<void *>(new args{new_socket, inet_ntoa(cliaddress.sin_addr), spool_dir}));
threads.push_back(tid); threads.push_back(tid);
new_socket = -1; new_socket = -1;
} }
@ -219,9 +229,12 @@ void printUsage()
void *clientCommunication(void *data) void *clientCommunication(void *data)
{ {
args* args = (struct args*) data;
char buffer[BUF]; char buffer[BUF];
int size; int size;
int *current_socket = (int *)data; int *current_socket = &args->socket;
std::string ip = args->ip;
std::string incomplete_message = ""; std::string incomplete_message = "";
@ -275,7 +288,7 @@ void *clientCommunication(void *data)
switch (cmd) { switch (cmd) {
case LOGIN: case LOGIN:
response = cmdLOGIN(lines, loggedInUsername); response = cmdLOGIN(lines, loggedInUsername, ip);
break; break;
case SEND: case SEND:
if (lines.size() < 5 || lines.back().compare(".") != 0) { if (lines.size() < 5 || lines.back().compare(".") != 0) {
@ -320,7 +333,7 @@ void *clientCommunication(void *data)
*current_socket = -1; *current_socket = -1;
} }
delete(current_socket); delete(args);
return NULL; return NULL;
} }
@ -394,7 +407,7 @@ inline void exiting()
printf("Saving... \n"); printf("Saving... \n");
} }
std::string cmdLOGIN(std::vector<std::string>& received, std::string& loggedInUsername) std::string cmdLOGIN(std::vector<std::string>& received, std::string& loggedInUsername, const std::string& ip)
{ {
if (received.size() < 3) { if (received.size() < 3) {
return "ERR\n"; return "ERR\n";
@ -428,8 +441,14 @@ std::string cmdLOGIN(std::vector<std::string>& received, std::string& loggedInUs
bindCredentials.bv_len = ldapBindPassword.length(); bindCredentials.bv_len = ldapBindPassword.length();
rc = ldap_sasl_bind_s(ldapHandle, ldapBindUser.c_str(), LDAP_SASL_SIMPLE, &bindCredentials, NULL, NULL, NULL); rc = ldap_sasl_bind_s(ldapHandle, ldapBindUser.c_str(), LDAP_SASL_SIMPLE, &bindCredentials, NULL, NULL, NULL);
if (rc != LDAP_SUCCESS) { if (rc != LDAP_SUCCESS) {
ip_ban::getInstance().failedAttempt(received.at(1), ip);
ldap_unbind_ext_s(ldapHandle, NULL, NULL); ldap_unbind_ext_s(ldapHandle, NULL, NULL);
return "ERR\n"; return "ERR\n";
}
if (ip_ban::getInstance().checkBanned(ip)) {
ldap_unbind_ext_s(ldapHandle, NULL, NULL);
return "ERR\n";
} }
loggedInUsername = received.at(1); loggedInUsername = received.at(1);