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
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))
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 <mutex>
mail::mail(std::string filename, std::string subject, std::string sender) :
filename(filename),

View File

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