87 lines
3.4 KiB
C++
87 lines
3.4 KiB
C++
#include <iostream>
|
|
#include <thread>
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <format>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
struct User{
|
|
std::vector<std::pair<std::string,int>>timeMap{};
|
|
uint32_t totalHits{0U};
|
|
};
|
|
|
|
int main(){
|
|
while(true){
|
|
uint32_t logEntries{5000};
|
|
uint32_t secondsSeparationOfAccess{120}; //In X seconds, the number of entries cannot be reached.
|
|
uint32_t tooFrequentAccess{600}; //Number of entries required in the seconds range specified to consider things spam.
|
|
std::unordered_map<std::string,User>userData;
|
|
std::unordered_set<std::string>ipBanList;
|
|
|
|
std::cout<<"Reading config file..."<<std::endl;
|
|
std::ifstream config{"/home/sigonasr2/.giteablocker-config"};
|
|
if(!config.good()){
|
|
std::cout<<"No config file found, using defaults."<<std::endl;
|
|
}else{
|
|
std::string line{};
|
|
std::getline(config,line);
|
|
logEntries=stoi(line);
|
|
std::getline(config,line);
|
|
secondsSeparationOfAccess=stoi(line);
|
|
std::getline(config,line);
|
|
tooFrequentAccess=stoi(line);
|
|
config.close();
|
|
}
|
|
std::cout<<std::format("\tLog Entries to Read: {} lines",logEntries)<<std::endl;
|
|
std::cout<<std::format("\tAccess Ban Limit: {} accesses / {} seconds",tooFrequentAccess,secondsSeparationOfAccess)<<std::endl;
|
|
|
|
std::cout<<"Reading journal..."<<std::endl;
|
|
std::system(std::format("journalctl -n {} -u gitea > /home/sigonasr2/gitea.access",logEntries).c_str());
|
|
std::cout<<"Beginning parsing..."<<std::endl;
|
|
std::ifstream file{"/home/sigonasr2/gitea.access"};
|
|
while(!file.eof()){
|
|
std::string line{};
|
|
std::getline(file,line);
|
|
if(line.length()>0){
|
|
size_t marker{};
|
|
if((marker=line.find(':'))==std::string::npos)continue;
|
|
if((marker=line.find(':',marker+1))==std::string::npos)continue;
|
|
if((marker=line.find(' ',marker+1))==std::string::npos)continue;
|
|
std::string time{line.substr(0,marker)};
|
|
size_t prevMarker=marker+1;
|
|
if((marker=line.find("for ",marker+1))==std::string::npos)continue;
|
|
prevMarker=(marker+=4);
|
|
if((marker=line.find(":",marker+1))==std::string::npos)continue;
|
|
std::string ipAddr{line.substr(prevMarker,marker-prevMarker)};
|
|
if(ipBanList.count(ipAddr)||ipAddr=="45.33.13.215")continue;
|
|
User&user{userData[ipAddr]};
|
|
const auto timeObjIt{std::find_if(user.timeMap.begin(),user.timeMap.end(),[&](const std::pair<std::string,int>&val){return val.first==time;})};
|
|
if(timeObjIt!=user.timeMap.end())(*timeObjIt).second++;
|
|
else user.timeMap.emplace_back(std::pair<std::string,int>{time,1});
|
|
user.totalHits++;
|
|
if(user.totalHits>tooFrequentAccess){
|
|
ipBanList.insert(ipAddr);
|
|
std::system(std::format("iptables -D INPUT -s {} -j DROP",ipAddr).c_str()); //In case the rule already existed, we are going to remove it first... No effect if it does not exist.
|
|
std::system(std::format("iptables -I INPUT 1 -s {} -j DROP",ipAddr).c_str());
|
|
std::cout<<std::format("New offender {} detected and added to banlist!",ipAddr)<<std::endl;
|
|
}
|
|
if(user.timeMap.size()>secondsSeparationOfAccess){
|
|
user.totalHits-=user.timeMap[0].second;
|
|
user.timeMap.erase(user.timeMap.begin());
|
|
}
|
|
}
|
|
}
|
|
std::cout<<std::format("{} offenders were banned!",ipBanList.size())<<std::endl;
|
|
std::system("service netfilter-persistent save");
|
|
std::cout<<"New Netfilter settings saved."<<std::endl;
|
|
std::this_thread::sleep_for(5min);
|
|
}
|
|
}
|