From c19d2dd7c1d91e58257cfe8c6299f6997e1e6f1a Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 14:58:18 +0100 Subject: [PATCH 001/114] Node.js version (not finished yet) --- .gitignore | 2 + .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/jsLibraryMappings.xml | 6 + .idea/jsLinters/eslint.xml | 7 + README.md | 5 - README_PL.md | 82 ------ default.config.js | 20 ++ ecosystem.config.js | 1 + eslint.config.mjs | 55 ++++ index.js | 112 ++++++++ install.sh | 261 ------------------- package-lock.json | 181 +++++++++++++ package.json | 34 +++ reporter.sh | 214 --------------- services/axios.js | 13 + utils/cache.js | 30 +++ utils/isLocalIP.js | 10 + utils/log.js | 10 + 18 files changed, 487 insertions(+), 562 deletions(-) create mode 100644 .gitignore create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/jsLibraryMappings.xml create mode 100644 .idea/jsLinters/eslint.xml delete mode 100644 README_PL.md create mode 100644 default.config.js create mode 100644 ecosystem.config.js create mode 100644 eslint.config.mjs create mode 100644 index.js delete mode 100644 install.sh create mode 100644 package-lock.json create mode 100644 package.json delete mode 100644 reporter.sh create mode 100644 services/axios.js create mode 100644 utils/cache.js create mode 100644 utils/isLocalIP.js create mode 100644 utils/log.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6da04de --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +config.js \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..03d9549 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..d23208f --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jsLinters/eslint.xml b/.idea/jsLinters/eslint.xml new file mode 100644 index 0000000..58b9bad --- /dev/null +++ b/.idea/jsLinters/eslint.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index b66dba7..3606594 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,3 @@ -
- [English] - [Polski] -
- # 🛡️ UFW AbuseIPDB Reporter A utility designed to analyze UFW firewall logs and report malicious IP addresses to the [AbuseIPDB](https://www.abuseipdb.com) database. To prevent redundant reporting of the same IP address within a short period, the tool uses a temporary cache file to track previously reported IPs. diff --git a/README_PL.md b/README_PL.md deleted file mode 100644 index fb6880f..0000000 --- a/README_PL.md +++ /dev/null @@ -1,82 +0,0 @@ -
- [English] - [Polski] -
- -# 🛡️ UFW AbuseIPDB Reporter -Narzędzie zaprojektowane do analizowania dzienników zapory sieciowej UFW i zgłaszania złośliwych adresów IP do bazy danych [AbuseIPDB](https://www.abuseipdb.com). -Aby zapobiec nadmiarowemu zgłaszaniu tego samego adresu IP w krótkim okresie, narzędzie wykorzystuje tymczasowy plik pamięci podręcznej do śledzenia wcześniej zgłoszonych adresów IP. - -Jeśli podoba Ci się to repozytorium lub uważasz je za przydatne, byłbym bardzo wdzięczny, za przyznanie mu gwiazdki ⭐. Wielkie dzięki! -Zobacz również to: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB) - -> [!IMPORTANT] -> Jeśli chcesz wprowadzić zmiany do jakichkolwiek pliku z tego repozytorium, zacznij od utworzenia [publicznego forka](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/fork). - - -## 📋 Wymagania -- **System operacyjny:** Linux z zainstalowanym i skonfigurowanym firewallem UFW. -- **Konto AbuseIPDB:** Wymagane jest konto w serwisie AbuseIPDB [z ważnym tokenem API](https://www.abuseipdb.com/account/api). Token API jest niezbędny. -- **Zainstalowane pakiety:** - - `wget` lub `curl`: Jedno z tych narzędzi jest wymagane do pobrania [skryptu instalacyjnego](install.sh) z repozytorium GitHub oraz do wysyłania zapytań do API AbuseIPDB. - - `jq`: Narzędzie do przetwarzania i parsowania danych w formacie JSON, zwracanych przez API AbuseIPDB. - - `openssl`: Używane do kodowania i dekodowania tokena API, aby zabezpieczyć dane uwierzytelniające. - - `tail`, `awk`, `grep`, `sed`: Standardowe narzędzia Unixowe wykorzystywane do przetwarzania tekstu i analizy logów. - - -## 🧪 Testowane systemy operacyjne -- **Ubuntu Server:** 20.04 & 22.04 - -*Jeśli dystrybucja, której używasz do uruchomienia tego narzędzia, nie jest wymieniona tutaj, ale działa poprawnie, utwórz nowy [Issue](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/issues) lub prześlij [Pull request](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/pulls).* - - -## 📥 Instalacja -### curl -```bash -bash <(curl -s https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/main/install.sh) -``` - -### wget -```bash -bash <(wget -qO- https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/main/install.sh) -``` - -Skrypt instalacyjny automatycznie pobierze i skonfiguruje narzędzie na komputerze użytkownika. Podczas procesu instalacji zostaniesz poproszony o podanie [tokenu API AbuseIPDB](https://www.abuseipdb.com/account/api). - - -## 🖥️ Użycie -Po pomyślnej instalacji skrypt będzie działać cały czas w tle, monitorując logi UFW i automatycznie zgłaszając złośliwe adresy IP. -Narzędzie nie wymaga dodatkowych działań użytkownika po instalacji. Warto jednak od czasu do czasu sprawdzić jego działanie oraz aktualizować skrypt na bieżąco (wywołując polecenie instalacyjne). - -Serwery otwarte na świat są nieustannie skanowane przez boty, które zazwyczaj szukają podatności lub jakichkolwiek innych luk w zabezpieczeniach. -Więc nie zdziw się, jeśli następnego dnia liczba zgłoszeń na AbuseIPDB przekroczy tysiąc. - -### 🔍 Sprawdzenie statusu usługi -```bash -sudo systemctl status abuseipdb-ufw.service -``` - -Aby zobaczyć bieżące logi generowane przez proces, użyj polecenia: -```bash -journalctl -u abuseipdb-ufw.service -f -``` - -### 📄 Przykładowe zgłoszenie -``` -Blocked by UFW (TCP on 80) -Source port: 28586 -TTL: 116 -Packet length: 48 -TOS: 0x08 - -This report (for 46.174.191.31) was generated by: -https://github.com/sefinek/UFW-AbuseIPDB-Reporter -``` - - -## 🤝 Rozwój -Jeśli chcesz przyczynić się do rozwoju tego projektu, śmiało stwórz nowy [Pull request](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/pulls). Z pewnością to docenię! - - -## 🔑 Licencja GPL-3.0 -Copyright 2024 © by [Sefinek](https://sefinek.net). Wszelkie prawa zastrzeżone. Zobacz plik [LICENSE](LICENSE), aby dowiedzieć się więcej. \ No newline at end of file diff --git a/default.config.js b/default.config.js new file mode 100644 index 0000000..1c88b22 --- /dev/null +++ b/default.config.js @@ -0,0 +1,20 @@ +exports.MAIN = { + LOG_FILE: 'D:\\test\\ufw.log', + CACHE_FILE: 'D:\\test\\ufw-abuseipdb-reporter.cache', + + ABUSEIPDB_API_KEY: '', + GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', + + REPORT_INTERVAL: 43200, +}; + +exports.REPORT_COMMENT = (timestamp, srcIp, dstIp, proto, spt, dpt, ttl, len, tos) => { + return `Blocked by UFW (${proto} on ${dpt}) +Source port: ${spt} +TTL: ${ttl || 'N/A'} +Packet length: ${len || 'N/A'} +TOS: ${tos || 'N/A'} + +This report (for ${srcIp}) was generated by: +https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove the URL to the repository of this script. I would be really grateful. 💙 +}; \ No newline at end of file diff --git a/ecosystem.config.js b/ecosystem.config.js new file mode 100644 index 0000000..a099545 --- /dev/null +++ b/ecosystem.config.js @@ -0,0 +1 @@ +module.exports = {}; \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..1b986f0 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,55 @@ +import js from '@eslint/js'; +import globals from 'globals'; + +export default [ + js.configs.recommended, + { + languageOptions: { + ecmaVersion: 2024, + globals: { + ...globals.node, + ...globals.es2024, + }, + }, + rules: { + 'arrow-spacing': [1, { before: true, after: true }], + 'comma-dangle': [1, { arrays: 'always-multiline', objects: 'always-multiline' }], + 'comma-spacing': 1, + 'comma-style': 'error', + 'curly': ['error', 'multi-line', 'consistent'], + 'dot-location': ['error', 'property'], + 'handle-callback-err': 'off', + 'indent': [1, 'tab'], + 'keyword-spacing': 1, + 'max-nested-callbacks': ['error', { max: 4 }], + 'max-statements-per-line': ['error', { max: 2 }], + 'no-console': 'off', + 'no-empty': 1, + 'no-empty-function': 1, + 'no-floating-decimal': 'error', + 'no-lonely-if': 1, + 'no-multi-spaces': 1, + 'no-multiple-empty-lines': [1, { max: 3, maxEOF: 1, maxBOF: 0 }], + 'no-shadow': ['error', { allow: ['err', 'resolve', 'reject'] }], + 'no-trailing-spaces': 1, + 'no-unreachable': 1, + 'no-unused-vars': 1, + 'no-use-before-define': ['error', { functions: false, classes: true }], + 'no-var': 'error', + 'object-curly-spacing': [1, 'always'], + 'prefer-const': 'error', + 'quotes': [1, 'single'], + 'semi': [1, 'always'], + 'sort-vars': 1, + 'space-before-blocks': 1, + 'space-before-function-paren': [1, { anonymous: 'never', named: 'never', asyncArrow: 'always' }], + 'space-in-parens': 1, + 'space-infix-ops': 1, + 'space-unary-ops': 1, + 'spaced-comment': 1, + 'wrap-regex': 1, + 'yoda': 'error', + }, + ignores: ['node_modules', '*min.js', '*bundle*', 'build/*', 'dist/*'], + }, +]; \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..53b165d --- /dev/null +++ b/index.js @@ -0,0 +1,112 @@ +const fs = require('node:fs'); +const chokidar = require('chokidar'); +const isLocalIP = require('./utils/isLocalIP.js'); +const { loadReportedIps, saveReportedIps, isIpReportedRecently, markIpAsReported } = require('./utils/cache.js'); +const log = require('./utils/log.js'); +const axios = require('./services/axios.js'); +const config = require('./config.js'); +const { LOG_FILE, ABUSEIPDB_API_KEY } = config.MAIN; + +let fileOffset = 0; + +const reportToAbuseIpDb = async (ip, categories, comment) => { + try { + const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ ip, categories, comment }), { + headers: { 'Key': ABUSEIPDB_API_KEY }, + }); + + log(0, `Successfully reported IP ${ip} (score: ${data.data.abuseConfidenceScore})`); + return true; + } catch (err) { + log(2, `${err.message}\n${JSON.stringify(err.response.data)}`); + return false; + } +}; + +const determineCategories = (proto, dpt) => { + const categories = { + TCP: { + 22: '14,22,18', 80: '14,21', 443: '14,21', 8080: '14,21', + 25: '14,11', 21: '14,5,18', 53: '14,1,2', 23: '14,15,18', + 3389: '14,15,18', 3306: '14,16', 6666: '14,8', + 6667: '14,8', 6668: '14,8', 6669: '14,8', 9999: '14,6', + }, + UDP: { + 53: '14,1,2', 123: '14,17', + }, + }; + + return categories[proto]?.[dpt] || '14'; +}; + +const processLogLine = async line => { + if (!line.includes('[UFW BLOCK]')) return log(1, `Ignoring line: ${line}`); + + const match = { + timestamp: line.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?/)[0], + srcIp: line.match(/SRC=([\d.]+)/)?.[1], + dstIp: line.match(/DST=([\d.]+)/)?.[1], + proto: line.match(/PROTO=(\S+)/)?.[1], + spt: line.match(/SPT=(\d+)/)?.[1], + dpt: line.match(/DPT=(\d+)/)?.[1], + ttl: line.match(/TTL=(\d+)/)?.[1], + len: line.match(/LEN=(\d+)/)?.[1], + tos: line.match(/TOS=(\S+)/)?.[1], + }; + + const { srcIp, proto, dpt } = match; + if (!srcIp) { + log(1, `Missing SRC in log line: ${line}`); + return; + } + + if (isLocalIP(srcIp)) { + log(0, `Ignoring local/private IP: ${srcIp}`); + return; + } + + if (isIpReportedRecently(srcIp)) { + log(0, `IP ${srcIp} reported recently`); + return; + } + + const categories = determineCategories(proto, dpt); + const comment = config.REPORT_COMMENT(match.timestamp, srcIp, match.dstIp, proto, match.spt, dpt, match.ttl, match.len, match.tos); + + log(0, `Reporting IP ${srcIp} (${proto} ${dpt}) with categories ${categories}`); + + if (await reportToAbuseIpDb(srcIp, categories, comment)) { + markIpAsReported(srcIp); + saveReportedIps(); + } +}; + +const startMonitoring = () => { + loadReportedIps(); + + if (!fs.existsSync(LOG_FILE)) { + log(2, `Log file ${LOG_FILE} does not exist.`); + return; + } + + fileOffset = fs.statSync(LOG_FILE).size; + + chokidar.watch(LOG_FILE, { persistent: true, ignoreInitial: true }) + .on('change', path => { + const stats = fs.statSync(path); + if (stats.size < fileOffset) { + log(1, 'File truncated. Resetting offset...'); + fileOffset = 0; + } + + fs.createReadStream(path, { start: fileOffset, encoding: 'utf8' }).on('data', chunk => { + chunk.split('\n').filter(line => line.trim()).forEach(processLogLine); + }).on('end', () => { + fileOffset = stats.size; + }); + }); + + log(0, `Now monitoring ${LOG_FILE}`); +}; + +startMonitoring(); \ No newline at end of file diff --git a/install.sh b/install.sh deleted file mode 100644 index 1f71044..0000000 --- a/install.sh +++ /dev/null @@ -1,261 +0,0 @@ -#!/bin/bash - -### -# https://github.com/sefinek/UFW-AbuseIPDB-Reporter -## - -VERSION="1.1.1" -DATE="01.12.2024" -REPO="https://github.com/sefinek/UFW-AbuseIPDB-Reporter" - -cat << "EOF" - _ _ ___ ____ ____ ____ - / \ | |__ _ _ ___ ___ |_ _| | _ \ | _ \ | __ ) - / _ \ | '_ \ | | | | / __| / _ \ | | | |_) | | | | | | _ \ - / ___ \ | |_) | | |_| | \__ \ | __/ | | | __/ | |_| | | |_) | - /_/ \_\_|_.__/ _ \__,_| |___/ \___| |___| |_| |____/ |____/ - - (_)_ __ | |_ ___ __ _ _ __ __ _| |_(_) ___ _ __ - | | '_ \| __/ _ \/ _` | '__/ _` | __| |/ _ \| '_ \ - | | | | | || __/ (_| | | | (_| | |_| | (_) | | | | - |_|_| |_|\__\___|\__, |_| \__,_|\__|_|\___/|_| |_| - |___/ - -EOF - -cat <> Made by sefinek.net || Version: $VERSION [$DATE] << - -This installer will configure UFW-AbuseIPDB-Reporter, a tool that analyzes -UFW firewall logs and reports IP addresses to AbuseIPDB. Remember to perform -updates periodically. You can join my Discord server to receive notifications -about the latest changes and more: https://discord.gg/53DBjTuzgZ -================================================================================ - -EOF - -# Function to download a file using either curl or wget -download_file() { - local url="$1" - local output="$2" - local user_agent="UFW-AbuseIPDB-Reporter/$VERSION (+$REPO)" - - if command -v curl >/dev/null 2>&1; then - echo "INFO: Using 'curl' to download the file..." - sudo curl -A "$user_agent" -o "$output" "$url" - elif command -v wget >/dev/null 2>&1; then - echo "INFO: 'curl' is not installed. Using 'wget' to download the file..." - sudo wget --header="User-Agent: $user_agent" -O "$output" "$url" - else - echo "FAIL: Neither 'curl' nor 'wget' is installed! Please install one of these packages and try running the script again." - exit 1 - fi -} - -# Ask -ask_user() { - local question="$1" - local response - - while true; do - read -rp "$ $question [Yes/no]: " response - case "${response,,}" in - yes|y) return 0;; - no|n) return 1;; - *) echo "Invalid input. Please answer 'yes' or 'no'." - echo;; - esac - done -} - -# ========================= CHECK FOR MISSING PACKAGES ========================= -required_packages=(ufw jq openssl) -missing_packages=() - -for pkg in "${required_packages[@]}"; do - if ! dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null | grep -q "install ok installed"; then - missing_packages+=("$pkg") - fi -done - -if [ ${#missing_packages[@]} -gt 0 ]; then - echo "WARN: The following packages are not installed: ${missing_packages[*]}" - if ! ask_user "Do you want to install them now?"; then - echo "FAIL: Missing dependencies packages. Installation cannot proceed without them." - exit 1 - fi - - echo "INFO: Installing missing dependencies: ${missing_packages[*]}" - if ! sudo apt-get update && sudo apt-get install -y "${missing_packages[@]}"; then - echo "FAIL: Failed to install the required dependencies. Aborting installation!" - exit 1 - fi - - echo -e "INFO: All required dependencies have been successfully installed.\n" -else - echo "INFO: Dependencies are already installed on this machine." -fi - - -# =========================== Check if the service already exists =========================== -if systemctl list-unit-files | grep -q '^abuseipdb-ufw.service'; then - echo "WARN: abuseipdb-ufw.service is already installed! If you plan to update or reinstall, choose 'Yes'." - if ask_user "Do you want to remove the existing service?"; then - sudo systemctl stop abuseipdb-ufw.service - sudo systemctl disable abuseipdb-ufw.service - sudo rm /etc/systemd/system/abuseipdb-ufw.service - sudo systemctl daemon-reload - else - echo -e "INFO: Existing service will not be removed\n" - fi -fi - - -# =========================== Prepare installation directory =========================== -install_dir="/usr/local/bin/UFW-AbuseIPDB-Reporter" -script_path="$install_dir/reporter.sh" -if [ -d "$install_dir" ]; then - echo "INFO: Directory $install_dir already exists. Removing it..." - if ! sudo rm -rf "$install_dir"; then - echo "FAIL: Something went wrong. Failed to remove existing directory $install_dir." - exit 1 - fi -fi - -echo "INFO: Creating installation directory at $install_dir..." -if ! sudo mkdir -p "$install_dir"; then - echo "FAIL: Something went wrong. Failed to create installation directory." - exit 1 -fi -echo - - -# =========================== Prepare reporter.sh script =========================== -GITHUB_URL="https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/main/reporter.sh" -echo "INFO: Downloading reporter.sh from $GITHUB_URL..." -if ! download_file "$GITHUB_URL" "$script_path"; then - echo "FAIL: Something went wrong while downloading the file from GitHub servers! Maybe try running this script as sudo?" - exit 1 -fi -echo "INFO: Saved reporter.sh at location $script_path" - -if ! sudo chmod +x "$script_path"; then - echo "FAIL: Failed to make reporter.sh executable." - exit 1 -fi -echo -e "INFO: reporter.sh has been made executable.\n" - - -# =========================== AbuseIPDB API token =========================== -max_attempts=4 -valid_token=false -for ((attempts = 0; attempts < max_attempts; attempts++)); do - read -rsp "$ Please enter your AbuseIPDB API token: " api_key - echo - - if [[ "$api_key" =~ ^[a-f0-9]{80}$ ]]; then - valid_token=true - break - fi - - attempts_left=$((max_attempts - attempts - 1)) - if (( attempts_left > 0 )); then - echo "WARN: Invalid API token format. Please enter an 80-character hexadecimal string. You have $attempts_left/$max_attempts attempts left." - fi -done - -if [[ "$valid_token" != true ]]; then - echo "FAIL: Maximum number of attempts reached. Installation aborted!" - exit 1 -fi - -# Encode the API token -token_file="$install_dir/.abuseipdb_token" -echo "INFO: Encoding data (file $token_file)..." -if ! echo -n "$api_key" | openssl enc -base64 | sudo tee "$token_file" >/dev/null; then - echo "FAIL: Something went wrong. Failed to encode API token." - exit 1 -fi - -# Update the ENCODED_API_KEY_FILE variable in reporter.sh by replacing the existing definition -echo "INFO: Updating ENCODED_API_KEY_FILE variable in reporter.sh..." -if ! sudo sed -i "s|^ENCODED_API_KEY_FILE=.*|ENCODED_API_KEY_FILE=\"$token_file\"|" "$script_path"; then - echo "FAIL: Failed to update ENCODED_API_KEY_FILE in reporter.sh." - exit 1 -fi - -echo "INFO: Setting permissions (chmod 644) for /var/log/ufw.log..." -sudo chmod 644 /var/log/ufw.log -echo - - -# =========================== abuseipdb-ufw.service =========================== -if ask_user "Would you like to add reporter.sh as a service and start it?"; then - service_file="/etc/systemd/system/abuseipdb-ufw.service" - echo "INFO: Setting up reporter.sh as a service" - if ! sudo bash -c "cat > $service_file" <<-EOF -[Unit] -Description=UFW AbuseIPDB Reporter -After=network.target -Documentation=$REPO - -[Service] -Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" -ExecStart=$script_path -Restart=always -User=$(logname) -WorkingDirectory=$install_dir -StandardOutput=journal -StandardError=journal - -[Install] -WantedBy=multi-user.target -EOF - then - echo "FAIL: Failed to create service file. Please check your permissions!" - exit 1 - fi - - sudo systemctl daemon-reload - - if sudo systemctl enable abuseipdb-ufw.service && sudo systemctl start abuseipdb-ufw.service; then - echo "INFO: Attempting to start the abuseipdb-ufw.service..." - else - echo "FAIL: Failed to enable or start the abuseipdb-ufw.service. Please check the system logs for details." - exit 1 - fi - - echo "INFO: Waiting 8 seconds to verify the script's stability..." - sleep 8 - - if sudo systemctl is-active --quiet abuseipdb-ufw.service; then - echo "INFO: abuseipdb-ufw.service is running!" - sudo systemctl status abuseipdb-ufw.service --no-pager - else - echo "FAIL: abuseipdb-ufw.service failed to start." - sudo systemctl status abuseipdb-ufw.service --no-pager - exit 1 - fi -else - echo -e "INFO: reporter.sh will not be added as a service. Running the script directly... Press ^C to stop.\n" - if "$script_path"; then - echo "INFO: reporter.sh executed successfully." - else - echo "FAIL: Failed to execute reporter.sh!" - exit 1 - fi -fi -echo - -# Prompt to add the service to autostart -if ask_user "Do you want to add abuseipdb-ufw.service to autostart?"; then - if sudo systemctl enable abuseipdb-ufw.service; then - echo "INFO: Great! abuseipdb-ufw.service has been added to autostart. Installation finished!" - echo "INFO: Run 'journalctl -u abuseipdb-ufw.service -f' to view more logs." - else - echo "FAIL: Failed to add abuseipdb-ufw.service to autostart!" - exit 1 - fi -else - echo "INFO: abuseipdb-ufw.service will not be added to autostart. Installation finished!" -fi diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..34e9794 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,181 @@ +{ + "name": "ufw-abuseipdb-reporter", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ufw-abuseipdb-reporter", + "version": "1.0.0", + "license": "GPL-3.0", + "dependencies": { + "axios": "^1.7.9", + "chokidar": "^4.0.3", + "ipaddr.js": "^2.2.0" + }, + "devDependencies": { + "@eslint/js": "^9.17.0", + "globals": "^15.14.0" + } + }, + "node_modules/@eslint/js": { + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.14.0.tgz", + "integrity": "sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "license": "MIT", + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ffb01ae --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "ufw-abuseipdb-reporter", + "version": "1.0.0", + "description": "", + "keywords": [ + "ufw", + "abuseipdb" + ], + "homepage": "https://github.com/sefinek/UFW-AbuseIPDB-Reporter", + "bugs": { + "url": "https://github.com/sefinek/UFW-AbuseIPDB-Reporter/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git" + }, + "license": "GPL-3.0", + "author": "Sefinek (https://sefinek.net)", + "type": "commonjs", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "up": "ncu -u && npm install && npm update && npm audit fix" + }, + "devDependencies": { + "@eslint/js": "^9.17.0", + "globals": "^15.14.0" + }, + "dependencies": { + "axios": "^1.7.9", + "chokidar": "^4.0.3", + "ipaddr.js": "^2.2.0" + } +} diff --git a/reporter.sh b/reporter.sh deleted file mode 100644 index db67649..0000000 --- a/reporter.sh +++ /dev/null @@ -1,214 +0,0 @@ -#!/bin/bash - -### -# https://github.com/sefinek/UFW-AbuseIPDB-Reporter -## - -LOG_FILE="/var/log/ufw.log" -ENCODED_API_KEY_FILE="./.abuseipdb_token" -REPORTED_IPS_FILE="/tmp/ufw-abuseipdb-reporter.cache" -REPORT_INTERVAL=43200 # 12h (in seconds) - -declare -A reported_ips - -log() { - local level="$1" - local message="$2" - echo "[$level] $message" -} - -# Check if the API key file exists and decode it -if [[ -f "$ENCODED_API_KEY_FILE" ]]; then - DECODED_API_KEY=$(openssl enc -d -base64 -in "$ENCODED_API_KEY_FILE") - if [[ -z "$DECODED_API_KEY" ]]; then - log "ERROR" "Failed to decode API key from $ENCODED_API_KEY_FILE" - exit 1 - fi -else - log "ERROR" "API key file not found at $ENCODED_API_KEY_FILE" - exit 1 -fi - -ABUSEIPDB_API_KEY="$DECODED_API_KEY" - -# Check if jq, curl, or wget packages are available -if ! command -v jq &> /dev/null; then - log "ERROR" "jq is not installed. Please install jq to run this script." - exit 1 -fi - -if ! command -v curl &> /dev/null && ! command -v wget &> /dev/null; then - log "ERROR" "Neither curl nor wget is available. Please install one of them to continue." - exit 1 -fi - -load_reported_ips() { - if [[ -f "$REPORTED_IPS_FILE" ]]; then - while IFS= read -r line; do - [[ -z "$line" ]] && continue - IFS=' ' read -r ip report_time <<< "$line" - if [[ -n "$ip" && -n "$report_time" ]]; then - reported_ips["$ip"]=$report_time - else - log "WARN" "Invalid line format: '$line'" - fi - done < "$REPORTED_IPS_FILE" - log "INFO" "Loaded ${#reported_ips[@]} IPs from $REPORTED_IPS_FILE" - else - log "INFO" "$REPORTED_IPS_FILE does not exist. No data to load." - fi -} - -save_reported_ips() { - : > "$REPORTED_IPS_FILE" - for ip in "${!reported_ips[@]}"; do - echo "$ip ${reported_ips[$ip]}" >> "$REPORTED_IPS_FILE" - done -} - -is_local_ip() { - local ip="$1" - [[ "$ip" =~ ^(10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.|127\.|fc|fd|fe80|::1) ]] -} - -report_to_abuseipdb() { - local ip="$1" categories="$2" proto="$3" spt="$4" dpt="$5" ttl="$6" len="$7" tos="$8" timestamp="$9" - - local comment="Blocked by UFW ($proto on $dpt) -Source port: $spt" - - [[ -n "$ttl" ]] && comment+=" -TTL: $ttl" - - [[ -n "$len" ]] && comment+=" -Packet length: $len" - - [[ -n "$tos" ]] && comment+=" -TOS: $tos" - - comment+=" - -This report (for $ip) was generated by: -https://github.com/sefinek/UFW-AbuseIPDB-Reporter" # Please do not remove the URL to the repository of this script. I would be really grateful. 💙 - - local res - if command -v curl >/dev/null 2>&1; then - res=$(curl -s -X POST "https://api.abuseipdb.com/api/v2/report" \ - --data-urlencode "ip=$ip" \ - --data-urlencode "categories=$categories" \ - --data-urlencode "comment=$comment" \ - -H "Key: $ABUSEIPDB_API_KEY" \ - -H "Accept: application/json") - elif command -v wget >/dev/null 2>&1; then - res=$(wget -qO- --post-data="ip=$ip&categories=$categories&comment=$comment" \ - --header="Key: $ABUSEIPDB_API_KEY" \ - --header="Accept: application/json" \ - "https://api.abuseipdb.com/api/v2/report") - else - log "ERROR" "Neither curl nor wget is available to send the report." - return 1 - fi - - local abuse_confidence_score - abuse_confidence_score=$(echo "$res" | jq -r '.data.abuseConfidenceScore') - - if [[ "$abuse_confidence_score" =~ ^[0-9]+$ ]]; then - log "INFO" "Successfully reported IP $ip to AbuseIPDB (score $abuse_confidence_score)" - return 0 - else - log "ERROR" "Failed to report IP $ip to AbuseIPDB: $res" - return 1 - fi -} - -is_ip_reported_recently() { - local ip="$1" - local current_time - current_time=$(date +%s) - - if [[ -v reported_ips["$ip"] ]]; then - local report_time=${reported_ips["$ip"]} - (( current_time - report_time < REPORT_INTERVAL )) && return 0 - fi - return 1 -} - -mark_ip_as_reported() { - local ip="$1" - reported_ips["$ip"]=$(date +%s) -} - -determine_categories() { - local proto="$1" - local dpt="$2" - - # See: https://www.abuseipdb.com/categories - case "$proto" in - "TCP") - case "$dpt" in - 22) echo "14,22,18" ;; # Port Scan | SSH | Brute-Force - 80 | 443 | 8080) echo "14,21" ;; # Port Scan | Web App Attack - 25) echo "14,11" ;; # Port Scan | Email Spam - 21) echo "14,5,18" ;; # Port Scan | FTP Brute-Force | Brute-Force - 53) echo "14,1,2" ;; # Port Scan | DNS Compromise | DNS Poisoning - 23 | 3389) echo "14,15,18" ;; # Port Scan | Hacking | Brute-Force - 3306) echo "14,16" ;; # Port Scan | SQL Injection - 6666 | 6667 | 6668 | 6669) echo "14,8" ;; # Port Scan | Fraud VoIP - 9999) echo "14,6" ;; # Port Scan | Ping of Death - *) echo "14" ;; # Port Scan - esac - ;; - "UDP") - case "$dpt" in - 53) echo "14,1,2" ;; # Port Scan | DNS Compromise | DNS Poisoning - 123) echo "14,17" ;; # Port Scan | Spoofing - *) echo "14" ;; # Port Scan - esac - ;; - *) echo "14" ;; # Port Scan - esac -} - -process_log_line() { - local line="$1" - if [[ "$line" == *"[UFW BLOCK]"* ]]; then - local timestamp src_ip proto spt dpt ttl len tos categories - - timestamp=$(echo "$line" | awk '{print $1, $2, $3}') - [[ -z "$timestamp" ]] && timestamp=$(date '+%Y-%m-%d %H:%M:%S') - src_ip=$(echo "$line" | grep -oP 'SRC=\K[^\s]+') - - if is_local_ip "$src_ip"; then - log "INFO" "Ignoring local IP: $src_ip" - return - fi - - proto=$(echo "$line" | grep -oP 'PROTO=\K[^\s]+') - spt=$(echo "$line" | grep -oP 'SPT=\K[^\s]+') - dpt=$(echo "$line" | grep -oP 'DPT=\K[^\s]+') - ttl=$(echo "$line" | grep -oP 'TTL=\K[^\s]+') - len=$(echo "$line" | grep -oP 'LEN=\K[^\s]+') - tos=$(echo "$line" | grep -oP 'TOS=\K[^\s]+') - - if is_ip_reported_recently "$src_ip"; then - log "INFO" "IP $src_ip ($proto) was reported recently" - return - fi - - categories=$(determine_categories "$proto" "$dpt") - - log "INFO" "Reporting IP $src_ip ($proto $dpt) with categories $categories..." - if report_to_abuseipdb "$src_ip" "$categories" "$proto" "$spt" "$dpt" "$ttl" "$len" "$tos" "$timestamp"; then - mark_ip_as_reported "$src_ip" - save_reported_ips - fi - fi -} - -load_reported_ips - -log "INFO" "Starting to monitor $LOG_FILE" - -tail -Fn0 "$LOG_FILE" | while read -r line; do - process_log_line "$line" -done diff --git a/services/axios.js b/services/axios.js new file mode 100644 index 0000000..f33a5ab --- /dev/null +++ b/services/axios.js @@ -0,0 +1,13 @@ +const axios = require('axios'); +const { version, homepage } = require('../config.js'); + +axios.defaults.headers.common = { + 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +${homepage})`, + 'Accept': 'application/json', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', +}; + +axios.defaults.timeout = 30000; + +module.exports = axios; \ No newline at end of file diff --git a/utils/cache.js b/utils/cache.js new file mode 100644 index 0000000..50b2b64 --- /dev/null +++ b/utils/cache.js @@ -0,0 +1,30 @@ +const fs = require('node:fs'); +const { CACHE_FILE, REPORT_INTERVAL } = require('../config.js').MAIN; +const log = require('./log.js'); + +const reportedIps = new Map(); + +const loadReportedIps = () => { + if (fs.existsSync(CACHE_FILE)) { + fs.readFileSync(CACHE_FILE, 'utf8') + .split('\n') + .forEach(line => { + const [ip, time] = line.split(' '); + if (ip && time) reportedIps.set(ip, Number(time)); + }); + log(0, `Loaded ${reportedIps.size} IPs from ${CACHE_FILE}`); + } else { + log(0, `${CACHE_FILE} does not exist. No data to load.`); + } +}; + +const saveReportedIps = () => fs.writeFileSync(CACHE_FILE, Array.from(reportedIps).map(([ip, time]) => `${ip} ${time}`).join('\n'), 'utf8'); + +const isIpReportedRecently = ip => { + const now = Math.floor(Date.now() / 1000); + return reportedIps.has(ip) && (now - reportedIps.get(ip) < REPORT_INTERVAL); +}; + +const markIpAsReported = ip => reportedIps.set(ip, Math.floor(Date.now() / 1000)); + +module.exports = { loadReportedIps, saveReportedIps, isIpReportedRecently, markIpAsReported }; \ No newline at end of file diff --git a/utils/isLocalIP.js b/utils/isLocalIP.js new file mode 100644 index 0000000..7d7ab80 --- /dev/null +++ b/utils/isLocalIP.js @@ -0,0 +1,10 @@ +const ipaddr = require('ipaddr.js'); + +module.exports = ip => { + const range = ipaddr.parse(ip).range(); + return [ + 'unspecified', 'multicast', 'linkLocal', 'loopback', 'reserved', 'benchmarking', + 'amt', 'broadcast', 'carrierGradeNat', 'private', 'as112', 'uniqueLocal', + 'ipv4Mapped', 'rfc6145', '6to4', 'teredo', 'as112v6', 'orchid2', 'droneRemoteIdProtocolEntityTags', + ].includes(range); +}; \ No newline at end of file diff --git a/utils/log.js b/utils/log.js new file mode 100644 index 0000000..b11361d --- /dev/null +++ b/utils/log.js @@ -0,0 +1,10 @@ +const levels = { + 0: { method: 'log', label: '[INFO]' }, + 1: { method: 'warn', label: '[WARN]' }, + 2: { method: 'error', label: '[FAIL]' }, +}; + +module.exports = (level, msg) => { + const { method, label } = levels[level] || { method: 'log', label: '[N/A]' }; + console[method](`${label} ${msg}`); +}; \ No newline at end of file From f032c5da38e688d3a558ece8a5ec5af9cbd637fe Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 14:59:21 +0100 Subject: [PATCH 002/114] =?UTF-8?q?##=20=F0=9F=93=8B=20Requirements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3606594..62987a7 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,8 @@ See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/ ## 📋 Requirements -- **Operating System:** Linux with UFW firewall installed and configured. -- **AbuseIPDB Account:** An account on the AbuseIPDB service [with a valid API token](https://www.abuseipdb.com/account/api). The API token is required. -- **Installed packages:** - - `wget` or `curl`: One of these tools is required to download the [installation script](install.sh) from the GitHub repository and to send requests to the AbuseIPDB API. - - `jq`: A tool for processing and parsing JSON data returned by the AbuseIPDB API. - - `openssl`: Used to encode and decode the API token to secure authentication data. - - `tail`, `awk`, `grep`, `sed`: Standard Unix tools used for text processing and log analysis. +- Node.js + npm +- Git ## 🧪 Tested operating systems From f95073d196d27f3616027e2926a6604366310605 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 15:19:30 +0100 Subject: [PATCH 003/114] Some fixes --- default.config.js | 35 ++++++++++++++++++++++++++++++++--- index.js | 39 +++++++++++++++++++-------------------- utils/cache.js | 6 +++--- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/default.config.js b/default.config.js index 1c88b22..e68f7e6 100644 --- a/default.config.js +++ b/default.config.js @@ -1,11 +1,11 @@ exports.MAIN = { - LOG_FILE: 'D:\\test\\ufw.log', - CACHE_FILE: 'D:\\test\\ufw-abuseipdb-reporter.cache', + LOG_FILE: '/var/log/ufw.log', + CACHE_FILE: '/tmp/ufw-abuseipdb-reporter.cache', ABUSEIPDB_API_KEY: '', GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', - REPORT_INTERVAL: 43200, + REPORT_INTERVAL: 12 * 60 * 60 * 1000, // 12h }; exports.REPORT_COMMENT = (timestamp, srcIp, dstIp, proto, spt, dpt, ttl, len, tos) => { @@ -17,4 +17,33 @@ TOS: ${tos || 'N/A'} This report (for ${srcIp}) was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove the URL to the repository of this script. I would be really grateful. 💙 +}; + +// See: https://www.abuseipdb.com/categories +exports.DETERMINE_CATEGORIES = (proto, dpt) => { + const categories = { + TCP: { + 22: '14,22,18', // Port Scan | SSH | Brute-Force + 80: '14,21', // Port Scan | Web App Attack + 443: '14,21', // Port Scan | Web App Attack + 8080: '14,21', // Port Scan | Web App Attack + 25: '14,11', // Port Scan | Email Spam + 21: '14,5,18', // Port Scan | FTP Brute-Force | Brute-Force + 53: '14,1,2', // Port Scan | DNS Compromise | DNS Poisoning + 23: '14,15,18', // Port Scan | Hacking | Brute-Force + 3389: '14,15,18', // Port Scan | Hacking | Brute-Force + 3306: '14,16', // Port Scan | SQL Injection + 6666: '14,8', // Port Scan | Fraud VoIP + 6667: '14,8', // Port Scan | Fraud VoIP + 6668: '14,8', // Port Scan | Fraud VoIP + 6669: '14,8', // Port Scan | Fraud VoIP + 9999: '14,6', // Port Scan | Ping of Death + }, + UDP: { + 53: '14,1,2', // Port Scan | DNS Compromise | DNS Poisoning + 123: '14,17', // Port Scan | Spoofing + }, + }; + + return categories[proto]?.[dpt] || '14'; // Port Scan }; \ No newline at end of file diff --git a/index.js b/index.js index 53b165d..75bd1d9 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ const fs = require('node:fs'); const chokidar = require('chokidar'); const isLocalIP = require('./utils/isLocalIP.js'); -const { loadReportedIps, saveReportedIps, isIpReportedRecently, markIpAsReported } = require('./utils/cache.js'); +const { reportedIps, loadReportedIps, saveReportedIps, isIpReportedRecently, markIpAsReported } = require('./utils/cache.js'); const log = require('./utils/log.js'); const axios = require('./services/axios.js'); const config = require('./config.js'); @@ -15,7 +15,7 @@ const reportToAbuseIpDb = async (ip, categories, comment) => { headers: { 'Key': ABUSEIPDB_API_KEY }, }); - log(0, `Successfully reported IP ${ip} (score: ${data.data.abuseConfidenceScore})`); + log(0, `Successfully reported IP ${ip} (abuse: ${data.data.abuseConfidenceScore}%)`); return true; } catch (err) { log(2, `${err.message}\n${JSON.stringify(err.response.data)}`); @@ -23,22 +23,6 @@ const reportToAbuseIpDb = async (ip, categories, comment) => { } }; -const determineCategories = (proto, dpt) => { - const categories = { - TCP: { - 22: '14,22,18', 80: '14,21', 443: '14,21', 8080: '14,21', - 25: '14,11', 21: '14,5,18', 53: '14,1,2', 23: '14,15,18', - 3389: '14,15,18', 3306: '14,16', 6666: '14,8', - 6667: '14,8', 6668: '14,8', 6669: '14,8', 9999: '14,6', - }, - UDP: { - 53: '14,1,2', 123: '14,17', - }, - }; - - return categories[proto]?.[dpt] || '14'; -}; - const processLogLine = async line => { if (!line.includes('[UFW BLOCK]')) return log(1, `Ignoring line: ${line}`); @@ -66,11 +50,26 @@ const processLogLine = async line => { } if (isIpReportedRecently(srcIp)) { - log(0, `IP ${srcIp} reported recently`); + const lastReportedTime = reportedIps.get(srcIp); + const elapsedTime = Math.floor(Date.now() / 1000 - lastReportedTime); + + const days = Math.floor(elapsedTime / 86400); + const hours = Math.floor((elapsedTime % 86400) / 3600); + const minutes = Math.floor((elapsedTime % 3600) / 60); + const seconds = elapsedTime % 60; + + const timeAgo = [ + days && `${days}d`, + hours && `${hours}h`, + minutes && `${minutes}m`, + (seconds || !days && !hours && !minutes) && `${seconds}s`, + ].filter(Boolean).join(' '); + + log(0, `IP ${srcIp} was last reported on ${new Date(lastReportedTime * 1000).toLocaleString()} (${timeAgo} ago)`); return; } - const categories = determineCategories(proto, dpt); + const categories = config.DETERMINE_CATEGORIES(proto, dpt); const comment = config.REPORT_COMMENT(match.timestamp, srcIp, match.dstIp, proto, match.spt, dpt, match.ttl, match.len, match.tos); log(0, `Reporting IP ${srcIp} (${proto} ${dpt}) with categories ${categories}`); diff --git a/utils/cache.js b/utils/cache.js index 50b2b64..42a5ac7 100644 --- a/utils/cache.js +++ b/utils/cache.js @@ -21,10 +21,10 @@ const loadReportedIps = () => { const saveReportedIps = () => fs.writeFileSync(CACHE_FILE, Array.from(reportedIps).map(([ip, time]) => `${ip} ${time}`).join('\n'), 'utf8'); const isIpReportedRecently = ip => { - const now = Math.floor(Date.now() / 1000); - return reportedIps.has(ip) && (now - reportedIps.get(ip) < REPORT_INTERVAL); + const reportedTime = reportedIps.get(ip); + return reportedTime && (Date.now() / 1000 - reportedTime < REPORT_INTERVAL / 1000); }; const markIpAsReported = ip => reportedIps.set(ip, Math.floor(Date.now() / 1000)); -module.exports = { loadReportedIps, saveReportedIps, isIpReportedRecently, markIpAsReported }; \ No newline at end of file +module.exports = { reportedIps, loadReportedIps, saveReportedIps, isIpReportedRecently, markIpAsReported }; \ No newline at end of file From a9118409cd40cc2c0f08b9180265af6fcbde96c9 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 15:22:52 +0100 Subject: [PATCH 004/114] Fix processLogLine --- index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 75bd1d9..7eb7547 100644 --- a/index.js +++ b/index.js @@ -27,15 +27,15 @@ const processLogLine = async line => { if (!line.includes('[UFW BLOCK]')) return log(1, `Ignoring line: ${line}`); const match = { - timestamp: line.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?/)[0], - srcIp: line.match(/SRC=([\d.]+)/)?.[1], - dstIp: line.match(/DST=([\d.]+)/)?.[1], - proto: line.match(/PROTO=(\S+)/)?.[1], - spt: line.match(/SPT=(\d+)/)?.[1], - dpt: line.match(/DPT=(\d+)/)?.[1], - ttl: line.match(/TTL=(\d+)/)?.[1], - len: line.match(/LEN=(\d+)/)?.[1], - tos: line.match(/TOS=(\S+)/)?.[1], + timestamp: line.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?/)?.[0] || null, + srcIp: line.match(/SRC=([\d.]+)/)?.[1] || null, + dstIp: line.match(/DST=([\d.]+)/)?.[1] || null, + proto: line.match(/PROTO=(\S+)/)?.[1] || null, + spt: line.match(/SPT=(\d+)/)?.[1] || null, + dpt: line.match(/DPT=(\d+)/)?.[1] || null, + ttl: line.match(/TTL=(\d+)/)?.[1] || null, + len: line.match(/LEN=(\d+)/)?.[1] || null, + tos: line.match(/TOS=(\S+)/)?.[1] || null, }; const { srcIp, proto, dpt } = match; From d2d3f27b2c5c57748f674df5bb28dc3bc628c293 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 15:28:49 +0100 Subject: [PATCH 005/114] 0.1.0 --- index.js | 4 +++- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 7eb7547..ac5c3ee 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ const { reportedIps, loadReportedIps, saveReportedIps, isIpReportedRecently, mar const log = require('./utils/log.js'); const axios = require('./services/axios.js'); const config = require('./config.js'); +const { version } = require('./package.json'); const { LOG_FILE, ABUSEIPDB_API_KEY } = config.MAIN; let fileOffset = 0; @@ -105,7 +106,8 @@ const startMonitoring = () => { }); }); - log(0, `Now monitoring ${LOG_FILE}`); + log(0, `==================== Version ${version} ====================`); + log(0, `Ready! Now monitoring: ${LOG_FILE}`); }; startMonitoring(); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 34e9794..a73791d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ufw-abuseipdb-reporter", - "version": "1.0.0", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ufw-abuseipdb-reporter", - "version": "1.0.0", + "version": "0.1.0", "license": "GPL-3.0", "dependencies": { "axios": "^1.7.9", diff --git a/package.json b/package.json index ffb01ae..8211d18 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ufw-abuseipdb-reporter", - "version": "1.0.0", + "version": "0.1.0", "description": "", "keywords": [ "ufw", From ce1b231dc87c062dee1cf9f229e9a9b9f80b3e56 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 15:40:28 +0100 Subject: [PATCH 006/114] Add `SERVER_IDENTIFIER` --- default.config.js | 12 ++++++++---- index.js | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/default.config.js b/default.config.js index e68f7e6..2765a57 100644 --- a/default.config.js +++ b/default.config.js @@ -1,15 +1,19 @@ exports.MAIN = { + // Server LOG_FILE: '/var/log/ufw.log', CACHE_FILE: '/tmp/ufw-abuseipdb-reporter.cache', + SERVER_IDENTIFIER: null, + // Reporting ABUSEIPDB_API_KEY: '', - GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', - REPORT_INTERVAL: 12 * 60 * 60 * 1000, // 12h + + // Project + GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', }; -exports.REPORT_COMMENT = (timestamp, srcIp, dstIp, proto, spt, dpt, ttl, len, tos) => { - return `Blocked by UFW (${proto} on ${dpt}) +exports.REPORT_COMMENT = (timestamp, srcIp, dstIp, proto, spt, dpt, ttl, len, tos, serverName) => { + return `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}] Source port: ${spt} TTL: ${ttl || 'N/A'} Packet length: ${len || 'N/A'} diff --git a/index.js b/index.js index ac5c3ee..0617b58 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,7 @@ const log = require('./utils/log.js'); const axios = require('./services/axios.js'); const config = require('./config.js'); const { version } = require('./package.json'); -const { LOG_FILE, ABUSEIPDB_API_KEY } = config.MAIN; +const { LOG_FILE, ABUSEIPDB_API_KEY, SERVER_IDENTIFIER } = config.MAIN; let fileOffset = 0; @@ -71,9 +71,9 @@ const processLogLine = async line => { } const categories = config.DETERMINE_CATEGORIES(proto, dpt); - const comment = config.REPORT_COMMENT(match.timestamp, srcIp, match.dstIp, proto, match.spt, dpt, match.ttl, match.len, match.tos); + const comment = config.REPORT_COMMENT(match.timestamp, srcIp, match.dstIp, proto, match.spt, dpt, match.ttl, match.len, match.tos, SERVER_IDENTIFIER); - log(0, `Reporting IP ${srcIp} (${proto} ${dpt}) with categories ${categories}`); + log(0, `Reporting IP ${srcIp} (${proto} ${dpt}) with categories: ${categories}`); if (await reportToAbuseIpDb(srcIp, categories, comment)) { markIpAsReported(srcIp); From 81e8f2c5f24bb350e06b1b12f34a82a26ec38be8 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 15:55:58 +0100 Subject: [PATCH 007/114] Update README.md etc --- README.md | 53 ++++++++++++++++++++------------------------- ecosystem.config.js | 27 ++++++++++++++++++++++- eslint.config.mjs | 48 ++++++++++++++++++++-------------------- 3 files changed, 73 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 62987a7..14a7106 100644 --- a/README.md +++ b/README.md @@ -10,29 +10,27 @@ See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/ ## 📋 Requirements -- Node.js + npm -- Git - - -## 🧪 Tested operating systems -- **Ubuntu Server:** 20.04 & 22.04 - -*If the distribution you're using to run this tool isn't listed here but works correctly, please create a new [Issue](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/issues) or submit a [Pull request](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/pulls).* +- [Node.js + npm](https://nodejs.org) +- [Git](https://git-scm.com) ## 📥 Installation -### curl ```bash -bash <(curl -s https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/main/install.sh) +cd ~ +git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git +cd UFW-AbuseIPDB-Reporter +npm install +cp default.config.js config.js +sudo chmod 644 /var/log/ufw.log +node . +^C +npm uninstall corepack -g +npm install pm2 -g +pm2 startup +[Wklej komendę wygenerowana przez pm2 startup] +pm2 save ``` -### wget -```bash -bash <(wget -qO- https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/main/install.sh) -``` - -The installation script will automatically download and configure the tool on your machine. During the installation process, you will be prompted to provide an [AbuseIPDB API token](https://www.abuseipdb.com/account/api). - ## 🖥️ Usage After successful installation, the script will run continuously in the background, monitoring UFW logs and automatically reporting malicious IP addresses. @@ -41,25 +39,20 @@ The tool requires no additional user action after installation. However, it's wo Servers open to the world are constantly scanned by bots, usually looking for vulnerabilities or other security gaps. So don't be surprised if the next day, the number of reports to AbuseIPDB exceeds a thousand. -### 🔍 Checking service status +### 🔍 Checking logs ```bash -sudo systemctl status abuseipdb-ufw.service -``` - -To see the current logs generated by the process, use the command: -```bash -journalctl -u abuseipdb-ufw.service -f +pm2 logs ufw-abuseipdb ``` ### 📄 Example report ``` -Blocked by UFW (TCP on 80) -Source port: 28586 -TTL: 116 -Packet length: 48 -TOS: 0x08 +Blocked by UFW on vserver1 [80/tcp] +Source port: 23639 +TTL: 247 +Packet length: 40 +TOS: 0x00 -This report (for 46.174.191.31) was generated by: +This report (for 45.156.129.52) was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter ``` diff --git a/ecosystem.config.js b/ecosystem.config.js index a099545..d29f7f6 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -1 +1,26 @@ -module.exports = {}; \ No newline at end of file +module.exports = { + apps: [{ + name: 'ufw-abuseipdb', + script: './index.js', + + // Logging configuration + log_date_format: 'HH:mm:ss.SSS DD.MM.YYYY', + merge_logs: true, + log_file: '/var/log/ufw-abuseipdb/combined.log', + out_file: '/var/log/ufw-abuseipdb/out.log', + error_file: '/var/log/ufw-abuseipdb/error.log', + + // Application restart policy settings + wait_ready: true, + autorestart: true, + max_restarts: 10, + min_uptime: 20000, + restart_delay: 5000, + exp_backoff_restart_delay: 3000, + + // Environment variables configuration + env: { + NODE_ENV: 'production', + }, + }], +}; \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs index 1b986f0..ae1f169 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -12,42 +12,42 @@ export default [ }, }, rules: { - 'arrow-spacing': [1, { before: true, after: true }], - 'comma-dangle': [1, { arrays: 'always-multiline', objects: 'always-multiline' }], - 'comma-spacing': 1, + 'arrow-spacing': ['warn', { before: true, after: true }], + 'comma-dangle': ['warn', { arrays: 'always-multiline', objects: 'always-multiline' }], + 'comma-spacing': 'warn', 'comma-style': 'error', 'curly': ['error', 'multi-line', 'consistent'], 'dot-location': ['error', 'property'], 'handle-callback-err': 'off', - 'indent': [1, 'tab'], - 'keyword-spacing': 1, + 'indent': ['warn', 'tab'], + 'keyword-spacing': 'warn', 'max-nested-callbacks': ['error', { max: 4 }], 'max-statements-per-line': ['error', { max: 2 }], 'no-console': 'off', - 'no-empty': 1, - 'no-empty-function': 1, + 'no-empty': 'warn', + 'no-empty-function': 'warn', 'no-floating-decimal': 'error', - 'no-lonely-if': 1, - 'no-multi-spaces': 1, - 'no-multiple-empty-lines': [1, { max: 3, maxEOF: 1, maxBOF: 0 }], + 'no-lonely-if': 'warn', + 'no-multi-spaces': 'warn', + 'no-multiple-empty-lines': ['warn', { max: 3, maxEOF: 1, maxBOF: 0 }], 'no-shadow': ['error', { allow: ['err', 'resolve', 'reject'] }], - 'no-trailing-spaces': 1, - 'no-unreachable': 1, - 'no-unused-vars': 1, + 'no-trailing-spaces': 'warn', + 'no-unreachable': 'warn', + 'no-unused-vars': 'warn', 'no-use-before-define': ['error', { functions: false, classes: true }], 'no-var': 'error', - 'object-curly-spacing': [1, 'always'], + 'object-curly-spacing': ['warn', 'always'], 'prefer-const': 'error', - 'quotes': [1, 'single'], - 'semi': [1, 'always'], - 'sort-vars': 1, - 'space-before-blocks': 1, - 'space-before-function-paren': [1, { anonymous: 'never', named: 'never', asyncArrow: 'always' }], - 'space-in-parens': 1, - 'space-infix-ops': 1, - 'space-unary-ops': 1, - 'spaced-comment': 1, - 'wrap-regex': 1, + 'quotes': ['warn', 'single'], + 'semi': ['warn', 'always'], + 'sort-vars': 'warn', + 'space-before-blocks': 'warn', + 'space-before-function-paren': ['warn', { anonymous: 'never', named: 'never', asyncArrow: 'always' }], + 'space-in-parens': 'warn', + 'space-infix-ops': 'warn', + 'space-unary-ops': 'warn', + 'spaced-comment': 'warn', + 'wrap-regex': 'warn', 'yoda': 'error', }, ignores: ['node_modules', '*min.js', '*bundle*', 'build/*', 'dist/*'], From 37ff738c2ae2b6e6a37d860d29e57dabb69f159c Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 15:56:22 +0100 Subject: [PATCH 008/114] Update README.md etc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 14a7106..24c6df3 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ node . npm uninstall corepack -g npm install pm2 -g pm2 startup -[Wklej komendę wygenerowana przez pm2 startup] +[Paste the command generated by pm2 startup] pm2 save ``` From a63e5a2cc4f6b7808450c422c83ea737650071e7 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 15:57:05 +0100 Subject: [PATCH 009/114] Update README.md etc --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 24c6df3..8de3d83 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ node . ^C npm uninstall corepack -g npm install pm2 -g +mkdir /var/log/ufw-abuseipdb +pm2 start pm2 startup [Paste the command generated by pm2 startup] pm2 save From 3c127dcfccdf2f585bf3c942499f1319c0d27b4f Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 15:57:17 +0100 Subject: [PATCH 010/114] Update README.md etc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8de3d83..0ed1167 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ node . ^C npm uninstall corepack -g npm install pm2 -g -mkdir /var/log/ufw-abuseipdb +sudo mkdir /var/log/ufw-abuseipdb pm2 start pm2 startup [Paste the command generated by pm2 startup] From 3f176d2ba523677028d5f051a579617666aa8447 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Thu, 19 Dec 2024 16:02:11 +0100 Subject: [PATCH 011/114] Update README.md etc --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0ed1167..bed4347 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ node . npm uninstall corepack -g npm install pm2 -g sudo mkdir /var/log/ufw-abuseipdb +sudo chown $USER:$USER /var/log/ufw-abuseipdb -R pm2 start pm2 startup [Paste the command generated by pm2 startup] From 1bd0ba2608490d9740d3ccd653cdcf68ee50d83a Mon Sep 17 00:00:00 2001 From: Sefinek Date: Fri, 20 Dec 2024 22:27:53 +0100 Subject: [PATCH 012/114] Skip UDP traffic --- index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.js b/index.js index 0617b58..046b40f 100644 --- a/index.js +++ b/index.js @@ -50,6 +50,14 @@ const processLogLine = async line => { return; } + // Report MUST NOT be of an attack where the source address is likely spoofed i.e. SYN floods and UDP floods. + // TCP connections can only be reported if they complete the three-way handshake. UDP connections cannot be reported. + // More: https://www.abuseipdb.com/reporting-policy + if (proto === 'UDP') { + log(0, `Skipping UDP traffic: SRC=${srcIp} DPT=${dpt}"`); + return; + } + if (isIpReportedRecently(srcIp)) { const lastReportedTime = reportedIps.get(srcIp); const elapsedTime = Math.floor(Date.now() / 1000 - lastReportedTime); From e1bfd289fdefeadadb02c9f0bb6bf8d616bcdeee Mon Sep 17 00:00:00 2001 From: Sefinek Date: Tue, 24 Dec 2024 23:47:58 +0100 Subject: [PATCH 013/114] Quality fixes --- default.config.js | 4 ++-- index.js | 41 +++++++++++++++++++++-------------------- package.json | 8 ++++---- services/axios.js | 4 ++-- utils/cache.js | 18 +++++++++--------- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/default.config.js b/default.config.js index 2765a57..d515d7a 100644 --- a/default.config.js +++ b/default.config.js @@ -1,8 +1,8 @@ exports.MAIN = { // Server - LOG_FILE: '/var/log/ufw.log', + UFW_FILE: '/var/log/ufw.log', CACHE_FILE: '/tmp/ufw-abuseipdb-reporter.cache', - SERVER_IDENTIFIER: null, + SERVER_ID: null, // Reporting ABUSEIPDB_API_KEY: '', diff --git a/index.js b/index.js index 046b40f..1be4652 100644 --- a/index.js +++ b/index.js @@ -1,16 +1,16 @@ const fs = require('node:fs'); const chokidar = require('chokidar'); const isLocalIP = require('./utils/isLocalIP.js'); -const { reportedIps, loadReportedIps, saveReportedIps, isIpReportedRecently, markIpAsReported } = require('./utils/cache.js'); +const { reportedIPs, loadReportedIPs, saveReportedIPs, isIPReportedRecently, markIPAsReported } = require('./utils/cache.js'); const log = require('./utils/log.js'); const axios = require('./services/axios.js'); const config = require('./config.js'); const { version } = require('./package.json'); -const { LOG_FILE, ABUSEIPDB_API_KEY, SERVER_IDENTIFIER } = config.MAIN; +const { UFW_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; let fileOffset = 0; -const reportToAbuseIpDb = async (ip, categories, comment) => { +const reportToAbuseIPDb = async (ip, categories, comment) => { try { const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ ip, categories, comment }), { headers: { 'Key': ABUSEIPDB_API_KEY }, @@ -58,8 +58,8 @@ const processLogLine = async line => { return; } - if (isIpReportedRecently(srcIp)) { - const lastReportedTime = reportedIps.get(srcIp); + if (isIPReportedRecently(srcIp)) { + const lastReportedTime = reportedIPs.get(srcIp); const elapsedTime = Math.floor(Date.now() / 1000 - lastReportedTime); const days = Math.floor(elapsedTime / 86400); @@ -79,27 +79,30 @@ const processLogLine = async line => { } const categories = config.DETERMINE_CATEGORIES(proto, dpt); - const comment = config.REPORT_COMMENT(match.timestamp, srcIp, match.dstIp, proto, match.spt, dpt, match.ttl, match.len, match.tos, SERVER_IDENTIFIER); + const comment = config.REPORT_COMMENT(match.timestamp, srcIp, match.dstIp, proto, match.spt, dpt, match.ttl, match.len, match.tos, SERVER_ID); log(0, `Reporting IP ${srcIp} (${proto} ${dpt}) with categories: ${categories}`); - if (await reportToAbuseIpDb(srcIp, categories, comment)) { - markIpAsReported(srcIp); - saveReportedIps(); + if (await reportToAbuseIPDb(srcIp, categories, comment)) { + markIPAsReported(srcIp); + saveReportedIPs(); } }; -const startMonitoring = () => { - loadReportedIps(); +(async () => { + log(0, `* Version: ${version}`); + log(0, `* Repository: ${GITHUB_REPO}`); - if (!fs.existsSync(LOG_FILE)) { - log(2, `Log file ${LOG_FILE} does not exist.`); + loadReportedIPs(); + + if (!fs.existsSync(UFW_FILE)) { + log(2, `Log file ${UFW_FILE} does not exist.`); return; } - fileOffset = fs.statSync(LOG_FILE).size; + fileOffset = fs.statSync(UFW_FILE).size; - chokidar.watch(LOG_FILE, { persistent: true, ignoreInitial: true }) + chokidar.watch(UFW_FILE, { persistent: true, ignoreInitial: true }) .on('change', path => { const stats = fs.statSync(path); if (stats.size < fileOffset) { @@ -114,8 +117,6 @@ const startMonitoring = () => { }); }); - log(0, `==================== Version ${version} ====================`); - log(0, `Ready! Now monitoring: ${LOG_FILE}`); -}; - -startMonitoring(); \ No newline at end of file + log(0, '====================================================================='); + log(0, `Ready! Now monitoring: ${UFW_FILE}`); +})(); \ No newline at end of file diff --git a/package.json b/package.json index 8211d18..e34f6e5 100644 --- a/package.json +++ b/package.json @@ -22,13 +22,13 @@ "test": "echo \"Error: no test specified\" && exit 1", "up": "ncu -u && npm install && npm update && npm audit fix" }, - "devDependencies": { - "@eslint/js": "^9.17.0", - "globals": "^15.14.0" - }, "dependencies": { "axios": "^1.7.9", "chokidar": "^4.0.3", "ipaddr.js": "^2.2.0" + }, + "devDependencies": { + "@eslint/js": "^9.17.0", + "globals": "^15.14.0" } } diff --git a/services/axios.js b/services/axios.js index f33a5ab..3534d7a 100644 --- a/services/axios.js +++ b/services/axios.js @@ -1,8 +1,8 @@ const axios = require('axios'); -const { version, homepage } = require('../config.js'); +const { version } = require('../config.js'); axios.defaults.headers.common = { - 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +${homepage})`, + 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +https://github.com/sefinek/UFW-AbuseIPDB-Reporter)`, 'Accept': 'application/json', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', diff --git a/utils/cache.js b/utils/cache.js index 42a5ac7..2538577 100644 --- a/utils/cache.js +++ b/utils/cache.js @@ -2,29 +2,29 @@ const fs = require('node:fs'); const { CACHE_FILE, REPORT_INTERVAL } = require('../config.js').MAIN; const log = require('./log.js'); -const reportedIps = new Map(); +const reportedIPs = new Map(); -const loadReportedIps = () => { +const loadReportedIPs = () => { if (fs.existsSync(CACHE_FILE)) { fs.readFileSync(CACHE_FILE, 'utf8') .split('\n') .forEach(line => { const [ip, time] = line.split(' '); - if (ip && time) reportedIps.set(ip, Number(time)); + if (ip && time) reportedIPs.set(ip, Number(time)); }); - log(0, `Loaded ${reportedIps.size} IPs from ${CACHE_FILE}`); + log(0, `Loaded ${reportedIPs.size} IPs from ${CACHE_FILE}`); } else { log(0, `${CACHE_FILE} does not exist. No data to load.`); } }; -const saveReportedIps = () => fs.writeFileSync(CACHE_FILE, Array.from(reportedIps).map(([ip, time]) => `${ip} ${time}`).join('\n'), 'utf8'); +const saveReportedIPs = () => fs.writeFileSync(CACHE_FILE, Array.from(reportedIPs).map(([ip, time]) => `${ip} ${time}`).join('\n'), 'utf8'); -const isIpReportedRecently = ip => { - const reportedTime = reportedIps.get(ip); +const isIPReportedRecently = ip => { + const reportedTime = reportedIPs.get(ip); return reportedTime && (Date.now() / 1000 - reportedTime < REPORT_INTERVAL / 1000); }; -const markIpAsReported = ip => reportedIps.set(ip, Math.floor(Date.now() / 1000)); +const markIPAsReported = ip => reportedIPs.set(ip, Math.floor(Date.now() / 1000)); -module.exports = { reportedIps, loadReportedIps, saveReportedIps, isIpReportedRecently, markIpAsReported }; \ No newline at end of file +module.exports = { reportedIPs, loadReportedIPs, saveReportedIPs, isIPReportedRecently, markIPAsReported }; \ No newline at end of file From 4df9c9c4beaf66aedd266f59c29fabcfe979a760 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 00:14:15 +0100 Subject: [PATCH 014/114] srcIp === getServerIP() --- default.config.js | 8 ++++---- index.js | 10 ++++++++-- {utils => services}/cache.js | 2 +- {utils => services}/isLocalIP.js | 0 services/serverIp.js | 26 ++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 7 deletions(-) rename {utils => services}/cache.js (96%) rename {utils => services}/isLocalIP.js (100%) create mode 100644 services/serverIp.js diff --git a/default.config.js b/default.config.js index d515d7a..068e774 100644 --- a/default.config.js +++ b/default.config.js @@ -2,25 +2,25 @@ exports.MAIN = { // Server UFW_FILE: '/var/log/ufw.log', CACHE_FILE: '/tmp/ufw-abuseipdb-reporter.cache', - SERVER_ID: null, + SERVER_ID: null, // The server name that will be visible in the reports. If you don't want to define it, leave the value as null. // Reporting ABUSEIPDB_API_KEY: '', REPORT_INTERVAL: 12 * 60 * 60 * 1000, // 12h // Project - GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', + GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', // If you are using a fork, provide the link to the forked repository here. }; exports.REPORT_COMMENT = (timestamp, srcIp, dstIp, proto, spt, dpt, ttl, len, tos, serverName) => { return `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}] -Source port: ${spt} +Source port: ${spt || 'N/A'} TTL: ${ttl || 'N/A'} Packet length: ${len || 'N/A'} TOS: ${tos || 'N/A'} This report (for ${srcIp}) was generated by: -https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove the URL to the repository of this script. I would be really grateful. 💙 +https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 }; // See: https://www.abuseipdb.com/categories diff --git a/index.js b/index.js index 1be4652..9a5fe63 100644 --- a/index.js +++ b/index.js @@ -1,9 +1,10 @@ const fs = require('node:fs'); const chokidar = require('chokidar'); -const isLocalIP = require('./utils/isLocalIP.js'); -const { reportedIPs, loadReportedIPs, saveReportedIPs, isIPReportedRecently, markIPAsReported } = require('./utils/cache.js'); +const isLocalIP = require('./services/isLocalIP.js'); +const { reportedIPs, loadReportedIPs, saveReportedIPs, isIPReportedRecently, markIPAsReported } = require('./services/cache.js'); const log = require('./utils/log.js'); const axios = require('./services/axios.js'); +const getServerIP = require('./services/serverIp.js'); const config = require('./config.js'); const { version } = require('./package.json'); const { UFW_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; @@ -45,6 +46,11 @@ const processLogLine = async line => { return; } + if (srcIp === getServerIP()) { + log(0, 'Ignoring own IP'); + return; + } + if (isLocalIP(srcIp)) { log(0, `Ignoring local/private IP: ${srcIp}`); return; diff --git a/utils/cache.js b/services/cache.js similarity index 96% rename from utils/cache.js rename to services/cache.js index 2538577..77871e8 100644 --- a/utils/cache.js +++ b/services/cache.js @@ -1,6 +1,6 @@ const fs = require('node:fs'); const { CACHE_FILE, REPORT_INTERVAL } = require('../config.js').MAIN; -const log = require('./log.js'); +const log = require('../utils/log.js'); const reportedIPs = new Map(); diff --git a/utils/isLocalIP.js b/services/isLocalIP.js similarity index 100% rename from utils/isLocalIP.js rename to services/isLocalIP.js diff --git a/services/serverIp.js b/services/serverIp.js new file mode 100644 index 0000000..b57a745 --- /dev/null +++ b/services/serverIp.js @@ -0,0 +1,26 @@ +const axios = require('./axios.js'); + +let address = null; + +const fetchIPAddress = async () => { + if (address) return; + + try { + const { data } = await axios.get('https://api.sefinek.net/api/v2/ip'); + if (data?.success && data?.message) { + address = data.message; + } else { + setTimeout(fetchIPAddress, 20 * 1000); + } + } catch { + setTimeout(fetchIPAddress, 25 * 1000); + } +}; + +if (process.env.NODE_ENV === 'production') { + (async () => fetchIPAddress())(); +} else { + address = '::ffff:127.0.0.1'; +} + +module.exports = () => address; \ No newline at end of file From f0003a7f5af5edb41bab2e248371b812c5d2dfd6 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 00:32:52 +0100 Subject: [PATCH 015/114] Update logData --- default.config.js | 30 ++++++++++++++++++++++++++++-- index.js | 31 ++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/default.config.js b/default.config.js index 068e774..843fb80 100644 --- a/default.config.js +++ b/default.config.js @@ -12,14 +12,40 @@ exports.MAIN = { GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', // If you are using a fork, provide the link to the forked repository here. }; -exports.REPORT_COMMENT = (timestamp, srcIp, dstIp, proto, spt, dpt, ttl, len, tos, serverName) => { +/** + * Generates a report submission to AbuseIPDB. + * @param {Object} logData + * @param {string|null} logData.timestamp + * @param {string|null} logData.In + * @param {string|null} logData.Out + * @param {string|null} logData.srcIp + * @param {string|null} logData.dstIp + * @param {string|null} logData.res + * @param {string|null} logData.tos + * @param {string|null} logData.prec + * @param {string|null} logData.ttl + * @param {string|null} logData.id + * @param {string|null} logData.proto + * @param {string|null} logData.spt + * @param {string|null} logData.dpt + * @param {string|null} logData.len + * @param {string|null} logData.urgp + * @param {string|null} logData.mac + * @param {string|null} logData.window + * @param {boolean} logData.syn + * @param {string|null} fullLog + * @param {string|null} serverName + * + * @returns {string} A formatted string report. + */ +exports.REPORT_COMMENT = ({ timestamp, In, Out, srcIp, dstIp, res, tos, prec, ttl, id, proto, spt, dpt, len, urgp, mac, window, syn }, fullLog, serverName) => { return `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}] Source port: ${spt || 'N/A'} TTL: ${ttl || 'N/A'} Packet length: ${len || 'N/A'} TOS: ${tos || 'N/A'} -This report (for ${srcIp}) was generated by: +This report was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 }; diff --git a/index.js b/index.js index 9a5fe63..55eb07c 100644 --- a/index.js +++ b/index.js @@ -28,19 +28,28 @@ const reportToAbuseIPDb = async (ip, categories, comment) => { const processLogLine = async line => { if (!line.includes('[UFW BLOCK]')) return log(1, `Ignoring line: ${line}`); - const match = { + const logData = { timestamp: line.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?/)?.[0] || null, - srcIp: line.match(/SRC=([\d.]+)/)?.[1] || null, - dstIp: line.match(/DST=([\d.]+)/)?.[1] || null, - proto: line.match(/PROTO=(\S+)/)?.[1] || null, - spt: line.match(/SPT=(\d+)/)?.[1] || null, - dpt: line.match(/DPT=(\d+)/)?.[1] || null, - ttl: line.match(/TTL=(\d+)/)?.[1] || null, - len: line.match(/LEN=(\d+)/)?.[1] || null, - tos: line.match(/TOS=(\S+)/)?.[1] || null, + In: line.match(/IN=([\d.]+)/)?.[1] || null, + Out: line.match(/OUT=([\d.]+)/)?.[1] || null, + srcIp: line.match(/SRC=([\d.]+)/)?.[1] || null, + dstIp: line.match(/DST=([\d.]+)/)?.[1] || null, + res: line.match(/RES=(\S+)/)?.[1] || null, + tos: line.match(/TOS=(\S+)/)?.[1] || null, + prec: line.match(/PREC=(\S+)/)?.[1] || null, + ttl: line.match(/TTL=(\d+)/)?.[1] || null, + id: line.match(/ID=(\d+)/)?.[1] || null, + proto: line.match(/PROTO=(\S+)/)?.[1] || null, + spt: line.match(/SPT=(\d+)/)?.[1] || null, + dpt: line.match(/DPT=(\d+)/)?.[1] || null, + len: line.match(/LEN=(\d+)/)?.[1] || null, + urgp: line.match(/URGP=(\d+)/)?.[1] || null, + mac: line.match(/MAC=([\w:]+)/)?.[1] || null, + window: line.match(/WINDOW=(\d+)/)?.[1] || null, + syn: !!line.includes('SYN'), }; - const { srcIp, proto, dpt } = match; + const { srcIp, proto, dpt } = logData; if (!srcIp) { log(1, `Missing SRC in log line: ${line}`); return; @@ -85,7 +94,7 @@ const processLogLine = async line => { } const categories = config.DETERMINE_CATEGORIES(proto, dpt); - const comment = config.REPORT_COMMENT(match.timestamp, srcIp, match.dstIp, proto, match.spt, dpt, match.ttl, match.len, match.tos, SERVER_ID); + const comment = config.REPORT_COMMENT(logData, line, SERVER_ID); log(0, `Reporting IP ${srcIp} (${proto} ${dpt}) with categories: ${categories}`); From 3dd173a53a3ac34c1a3abfca1cb9ba367c8c27e9 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 00:40:19 +0100 Subject: [PATCH 016/114] Fix --- default.config.js | 1 - services/axios.js | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/default.config.js b/default.config.js index 843fb80..a7350d5 100644 --- a/default.config.js +++ b/default.config.js @@ -35,7 +35,6 @@ exports.MAIN = { * @param {boolean} logData.syn * @param {string|null} fullLog * @param {string|null} serverName - * * @returns {string} A formatted string report. */ exports.REPORT_COMMENT = ({ timestamp, In, Out, srcIp, dstIp, res, tos, prec, ttl, id, proto, spt, dpt, len, urgp, mac, window, syn }, fullLog, serverName) => { diff --git a/services/axios.js b/services/axios.js index 3534d7a..a093ccf 100644 --- a/services/axios.js +++ b/services/axios.js @@ -1,8 +1,9 @@ const axios = require('axios'); -const { version } = require('../config.js'); +const { version } = require('../package.json'); +const { GITHUB_REPO } = require('../config.js'); axios.defaults.headers.common = { - 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +https://github.com/sefinek/UFW-AbuseIPDB-Reporter)`, + 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +${GITHUB_REPO})`, 'Accept': 'application/json', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', From 5785d6d6cf8a2c164168e197b24a881602bbb6e8 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 00:41:27 +0100 Subject: [PATCH 017/114] Fix --- services/axios.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/axios.js b/services/axios.js index a093ccf..80fc96e 100644 --- a/services/axios.js +++ b/services/axios.js @@ -1,9 +1,9 @@ const axios = require('axios'); const { version } = require('../package.json'); -const { GITHUB_REPO } = require('../config.js'); +const { main } = require('../config.js'); axios.defaults.headers.common = { - 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +${GITHUB_REPO})`, + 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +${main.GITHUB_REPO})`, 'Accept': 'application/json', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', From 2c8f93a95bcf2948bcbd83f301ffbeee4c49d107 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 00:42:06 +0100 Subject: [PATCH 018/114] Fix --- services/axios.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/axios.js b/services/axios.js index 80fc96e..3feccab 100644 --- a/services/axios.js +++ b/services/axios.js @@ -1,9 +1,9 @@ const axios = require('axios'); const { version } = require('../package.json'); -const { main } = require('../config.js'); +const { GITHUB_REPO } = require('../config.js').MAIN; axios.defaults.headers.common = { - 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +${main.GITHUB_REPO})`, + 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +${GITHUB_REPO})`, 'Accept': 'application/json', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', From 144cf8eea2864ced5fa8e23d854fa984074058f6 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 00:45:30 +0100 Subject: [PATCH 019/114] Update --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 55eb07c..30ecba4 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,7 @@ const reportToAbuseIPDb = async (ip, categories, comment) => { log(0, `Successfully reported IP ${ip} (abuse: ${data.data.abuseConfidenceScore}%)`); return true; } catch (err) { - log(2, `${err.message}\n${JSON.stringify(err.response.data)}`); + log(2, `${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); return false; } }; From 73a8fb269fc087d60cccd3ead7f299c2e9a2bb30 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 00:46:12 +0100 Subject: [PATCH 020/114] Update --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 30ecba4..5bc251b 100644 --- a/index.js +++ b/index.js @@ -69,7 +69,7 @@ const processLogLine = async line => { // TCP connections can only be reported if they complete the three-way handshake. UDP connections cannot be reported. // More: https://www.abuseipdb.com/reporting-policy if (proto === 'UDP') { - log(0, `Skipping UDP traffic: SRC=${srcIp} DPT=${dpt}"`); + log(0, `Skipping UDP traffic: SRC=${srcIp} DPT=${dpt}`); return; } From d935ad871afbe5465bf7cdd376fd643d84e9409b Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 00:59:22 +0100 Subject: [PATCH 021/114] Fixes --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 5bc251b..a039088 100644 --- a/index.js +++ b/index.js @@ -96,7 +96,7 @@ const processLogLine = async line => { const categories = config.DETERMINE_CATEGORIES(proto, dpt); const comment = config.REPORT_COMMENT(logData, line, SERVER_ID); - log(0, `Reporting IP ${srcIp} (${proto} ${dpt}) with categories: ${categories}`); + log(0, `Reporting ${srcIp} (${dpt}/${proto}) with categories: ${categories}`); if (await reportToAbuseIPDb(srcIp, categories, comment)) { markIPAsReported(srcIp); @@ -132,6 +132,6 @@ const processLogLine = async line => { }); }); - log(0, '====================================================================='); log(0, `Ready! Now monitoring: ${UFW_FILE}`); + log(0, '====================================================================='); })(); \ No newline at end of file From 58e45103bcf569a41b8d79a76f65d3a3d8231796 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:03:26 +0100 Subject: [PATCH 022/114] Fixes --- index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index a039088..e9986dd 100644 --- a/index.js +++ b/index.js @@ -11,13 +11,13 @@ const { UFW_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; let fileOffset = 0; -const reportToAbuseIPDb = async (ip, categories, comment) => { +const reportToAbuseIPDb = async (logData, categories, comment) => { try { - const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ ip, categories, comment }), { + const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ ip: logData.ip, categories, comment }), { headers: { 'Key': ABUSEIPDB_API_KEY }, }); - log(0, `Successfully reported IP ${ip} (abuse: ${data.data.abuseConfidenceScore}%)`); + log(0, `Successfully reported ${logData.srcIp} (${logData.dpt}/${logData.proto}) with categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); return true; } catch (err) { log(2, `${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); @@ -96,9 +96,7 @@ const processLogLine = async line => { const categories = config.DETERMINE_CATEGORIES(proto, dpt); const comment = config.REPORT_COMMENT(logData, line, SERVER_ID); - log(0, `Reporting ${srcIp} (${dpt}/${proto}) with categories: ${categories}`); - - if (await reportToAbuseIPDb(srcIp, categories, comment)) { + if (await reportToAbuseIPDb(logData, categories, comment)) { markIPAsReported(srcIp); saveReportedIPs(); } From 3c1fa403b33f34f624b33ff276896c04b833c44b Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:04:02 +0100 Subject: [PATCH 023/114] Fixes --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index e9986dd..7a5e6b3 100644 --- a/index.js +++ b/index.js @@ -13,7 +13,7 @@ let fileOffset = 0; const reportToAbuseIPDb = async (logData, categories, comment) => { try { - const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ ip: logData.ip, categories, comment }), { + const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ ip: logData.srcIp, categories, comment }), { headers: { 'Key': ABUSEIPDB_API_KEY }, }); From 5425d1ff03b767405415e758c77d2a684391a253 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:06:03 +0100 Subject: [PATCH 024/114] Fixes --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 7a5e6b3..1b877cb 100644 --- a/index.js +++ b/index.js @@ -17,7 +17,7 @@ const reportToAbuseIPDb = async (logData, categories, comment) => { headers: { 'Key': ABUSEIPDB_API_KEY }, }); - log(0, `Successfully reported ${logData.srcIp} (${logData.dpt}/${logData.proto}) with categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); + log(0, `Successfully reported ${logData.srcIp} (${logData.dpt}/${logData.proto}); Categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); return true; } catch (err) { log(2, `${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); From 09d0a54db37454e57f8c24c536d39c9237058a78 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:06:39 +0100 Subject: [PATCH 025/114] Fixes --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 1b877cb..5ab7487 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,7 @@ const reportToAbuseIPDb = async (logData, categories, comment) => { log(0, `Successfully reported ${logData.srcIp} (${logData.dpt}/${logData.proto}); Categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); return true; } catch (err) { - log(2, `${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); + log(2, `Failed to report ${logData.srcIp} (${logData.dpt}/${logData.proto}); ${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); return false; } }; From 25376cfb75c968ed62e103c63d0324ad91a92a82 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:08:34 +0100 Subject: [PATCH 026/114] Fixes --- default.config.js | 57 +++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/default.config.js b/default.config.js index a7350d5..0da7a13 100644 --- a/default.config.js +++ b/default.config.js @@ -12,6 +12,7 @@ exports.MAIN = { GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', // If you are using a fork, provide the link to the forked repository here. }; + /** * Generates a report submission to AbuseIPDB. * @param {Object} logData @@ -37,8 +38,8 @@ exports.MAIN = { * @param {string|null} serverName * @returns {string} A formatted string report. */ -exports.REPORT_COMMENT = ({ timestamp, In, Out, srcIp, dstIp, res, tos, prec, ttl, id, proto, spt, dpt, len, urgp, mac, window, syn }, fullLog, serverName) => { - return `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}] +exports.REPORT_COMMENT = ({ timestamp, In, Out, srcIp, dstIp, res, tos, prec, ttl, id, proto, spt, dpt, len, urgp, mac, window, syn }, fullLog, serverName) => + `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}] Source port: ${spt || 'N/A'} TTL: ${ttl || 'N/A'} Packet length: ${len || 'N/A'} @@ -46,33 +47,31 @@ TOS: ${tos || 'N/A'} This report was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 -}; + // See: https://www.abuseipdb.com/categories -exports.DETERMINE_CATEGORIES = (proto, dpt) => { - const categories = { - TCP: { - 22: '14,22,18', // Port Scan | SSH | Brute-Force - 80: '14,21', // Port Scan | Web App Attack - 443: '14,21', // Port Scan | Web App Attack - 8080: '14,21', // Port Scan | Web App Attack - 25: '14,11', // Port Scan | Email Spam - 21: '14,5,18', // Port Scan | FTP Brute-Force | Brute-Force - 53: '14,1,2', // Port Scan | DNS Compromise | DNS Poisoning - 23: '14,15,18', // Port Scan | Hacking | Brute-Force - 3389: '14,15,18', // Port Scan | Hacking | Brute-Force - 3306: '14,16', // Port Scan | SQL Injection - 6666: '14,8', // Port Scan | Fraud VoIP - 6667: '14,8', // Port Scan | Fraud VoIP - 6668: '14,8', // Port Scan | Fraud VoIP - 6669: '14,8', // Port Scan | Fraud VoIP - 9999: '14,6', // Port Scan | Ping of Death - }, - UDP: { - 53: '14,1,2', // Port Scan | DNS Compromise | DNS Poisoning - 123: '14,17', // Port Scan | Spoofing - }, - }; +const categories = { + TCP: { + 22: '14,22,18', // Port Scan | SSH | Brute-Force + 80: '14,21', // Port Scan | Web App Attack + 443: '14,21', // Port Scan | Web App Attack + 8080: '14,21', // Port Scan | Web App Attack + 25: '14,11', // Port Scan | Email Spam + 21: '14,5,18', // Port Scan | FTP Brute-Force | Brute-Force + 53: '14,1,2', // Port Scan | DNS Compromise | DNS Poisoning + 23: '14,15,18', // Port Scan | Hacking | Brute-Force + 3389: '14,15,18', // Port Scan | Hacking | Brute-Force + 3306: '14,16', // Port Scan | SQL Injection + 6666: '14,8', // Port Scan | Fraud VoIP + 6667: '14,8', // Port Scan | Fraud VoIP + 6668: '14,8', // Port Scan | Fraud VoIP + 6669: '14,8', // Port Scan | Fraud VoIP + 9999: '14,6', // Port Scan | Ping of Death + }, + UDP: { + 53: '14,1,2', // Port Scan | DNS Compromise | DNS Poisoning + 123: '14,17', // Port Scan | Spoofing + }, +}; - return categories[proto]?.[dpt] || '14'; // Port Scan -}; \ No newline at end of file +exports.DETERMINE_CATEGORIES = (proto, dpt) => categories[proto]?.[dpt] || '14'; // Default: Port Scan \ No newline at end of file From 83571456df95c8a5eef6123103271df0060e2dd8 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:10:11 +0100 Subject: [PATCH 027/114] Fixes --- default.config.js | 2 +- index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/default.config.js b/default.config.js index 0da7a13..2571087 100644 --- a/default.config.js +++ b/default.config.js @@ -74,4 +74,4 @@ const categories = { }, }; -exports.DETERMINE_CATEGORIES = (proto, dpt) => categories[proto]?.[dpt] || '14'; // Default: Port Scan \ No newline at end of file +exports.DETERMINE_CATEGORIES = ({ proto, dpt }) => categories[proto]?.[dpt] || '14'; // Default: Port Scan \ No newline at end of file diff --git a/index.js b/index.js index 5ab7487..9bfefe2 100644 --- a/index.js +++ b/index.js @@ -93,7 +93,7 @@ const processLogLine = async line => { return; } - const categories = config.DETERMINE_CATEGORIES(proto, dpt); + const categories = config.DETERMINE_CATEGORIES(logData); const comment = config.REPORT_COMMENT(logData, line, SERVER_ID); if (await reportToAbuseIPDb(logData, categories, comment)) { From 0281b6dd8ce1ce8b27492cce491abec10df22fa3 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:11:20 +0100 Subject: [PATCH 028/114] Fixes --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 9bfefe2..b2cd51c 100644 --- a/index.js +++ b/index.js @@ -17,7 +17,7 @@ const reportToAbuseIPDb = async (logData, categories, comment) => { headers: { 'Key': ABUSEIPDB_API_KEY }, }); - log(0, `Successfully reported ${logData.srcIp} (${logData.dpt}/${logData.proto}); Categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); + log(0, `Reported ${logData.srcIp} (${logData.dpt}/${logData.proto}); Categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); return true; } catch (err) { log(2, `Failed to report ${logData.srcIp} (${logData.dpt}/${logData.proto}); ${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); @@ -89,7 +89,7 @@ const processLogLine = async line => { (seconds || !days && !hours && !minutes) && `${seconds}s`, ].filter(Boolean).join(' '); - log(0, `IP ${srcIp} was last reported on ${new Date(lastReportedTime * 1000).toLocaleString()} (${timeAgo} ago)`); + log(0, `${srcIp} was last reported on ${new Date(lastReportedTime * 1000).toLocaleString()} (${timeAgo} ago)`); return; } From 3986ff4e803fc596c1aaa440ade240b07c559426 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:16:10 +0100 Subject: [PATCH 029/114] Fixes --- default.config.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/default.config.js b/default.config.js index 2571087..81737f9 100644 --- a/default.config.js +++ b/default.config.js @@ -48,6 +48,10 @@ TOS: ${tos || 'N/A'} This report was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 +// Alternative log: +// exports.REPORT_COMMENT = ({ timestamp, In, Out, srcIp, dstIp, res, tos, prec, ttl, id, proto, spt, dpt, len, urgp, mac, window, syn }, fullLog, serverName) => +// `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}]. Source port ${spt || 'N/A'}. Packet length ${len || 'N/A'}. Report was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 + // See: https://www.abuseipdb.com/categories const categories = { From a5487950675ff7972b0b9567d9082e6c912c8c9b Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:19:20 +0100 Subject: [PATCH 030/114] Fixes --- default.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.config.js b/default.config.js index 81737f9..e254cbb 100644 --- a/default.config.js +++ b/default.config.js @@ -50,7 +50,7 @@ https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this // Alternative log: // exports.REPORT_COMMENT = ({ timestamp, In, Out, srcIp, dstIp, res, tos, prec, ttl, id, proto, spt, dpt, len, urgp, mac, window, syn }, fullLog, serverName) => -// `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}]. Source port ${spt || 'N/A'}. Packet length ${len || 'N/A'}. Report was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 +// `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 // See: https://www.abuseipdb.com/categories From 20a6f260773abbcc127799c85cbb0d0a8134e49f Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:25:31 +0100 Subject: [PATCH 031/114] Fixes --- default.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.config.js b/default.config.js index e254cbb..af73952 100644 --- a/default.config.js +++ b/default.config.js @@ -48,7 +48,7 @@ TOS: ${tos || 'N/A'} This report was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 -// Alternative log: +// Alternative version: // exports.REPORT_COMMENT = ({ timestamp, In, Out, srcIp, dstIp, res, tos, prec, ttl, id, proto, spt, dpt, len, urgp, mac, window, syn }, fullLog, serverName) => // `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 From 3c90e5f380504a7cf44432dd64957cb06636d380 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:30:29 +0100 Subject: [PATCH 032/114] Update README.md --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bed4347..af0feef 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/ ## 📋 Requirements - [Node.js + npm](https://nodejs.org) +- [PM2](https://www.npmjs.com/package/pm2) - [Git](https://git-scm.com) @@ -47,7 +48,8 @@ So don't be surprised if the next day, the number of reports to AbuseIPDB exceed pm2 logs ufw-abuseipdb ``` -### 📄 Example report +### 📄 Example reports +#### 1 ``` Blocked by UFW on vserver1 [80/tcp] Source port: 23639 @@ -55,10 +57,15 @@ TTL: 247 Packet length: 40 TOS: 0x00 -This report (for 45.156.129.52) was generated by: +This report was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter ``` +#### 2 +``` +Blocked by UFW on vserver1 [30049/tcp]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter +``` + ## 🤝 Development If you want to contribute to the development of this project, feel free to create a new [Pull request](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/pulls). I will definitely appreciate it! From a7b2bf6ed0911a64023b975cb5bb32da25680d27 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:32:43 +0100 Subject: [PATCH 033/114] process?.send --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index b2cd51c..28ed905 100644 --- a/index.js +++ b/index.js @@ -130,6 +130,8 @@ const processLogLine = async line => { }); }); + if (process?.send) process.send('ready'); + log(0, `Ready! Now monitoring: ${UFW_FILE}`); log(0, '====================================================================='); })(); \ No newline at end of file From 576dfa9c45ba9e64c9b98db76bee75aa28e55ee9 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:36:13 +0100 Subject: [PATCH 034/114] process?.send --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index af0feef..3778a62 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,14 @@ pm2 startup pm2 save ``` +## Migration from the bash version +```bash +sudo systemctl stop abuseipdb-ufw.service +sudo systemctl disable abuseipdb-ufw.service +sudo rm /etc/systemd/system/abuseipdb-ufw.service +sudo systemctl daemon-reload +``` + ## 🖥️ Usage After successful installation, the script will run continuously in the background, monitoring UFW logs and automatically reporting malicious IP addresses. From e5fd2cbc0f294d5f09a64c4779ee3e8f07bb74f0 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:38:12 +0100 Subject: [PATCH 035/114] process?.send --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3778a62..1f96cab 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,13 @@ pm2 startup pm2 save ``` -## Migration from the bash version +## 🗑️ Remove the old version ```bash sudo systemctl stop abuseipdb-ufw.service sudo systemctl disable abuseipdb-ufw.service sudo rm /etc/systemd/system/abuseipdb-ufw.service sudo systemctl daemon-reload +sudo rm -r /usr/local/bin/UFW-AbuseIPDB-Reporter ``` From cb4f2fc87e49040c049d77f2a5b63c44a2979392 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:42:07 +0100 Subject: [PATCH 036/114] process?.send --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 1f96cab..efc6e4d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ A utility designed to analyze UFW firewall logs and report malicious IP addresses to the [AbuseIPDB](https://www.abuseipdb.com) database. To prevent redundant reporting of the same IP address within a short period, the tool uses a temporary cache file to track previously reported IPs. +This project was previously written in Bash, but it has been rewritten in [Node.js](https://nodejs.org). All my integration tools are currently written in Node, hence the change. +If you were using the old version, uninstall it as it will no longer be supported. + If you like this repository or find it useful, I would greatly appreciate it if you could give it a star ⭐. Thanks a lot! See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB) From 8cb727fad93386cce452d9c4e1b1590d02eed702 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:43:02 +0100 Subject: [PATCH 037/114] process?.send --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index efc6e4d..b6d69eb 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A utility designed to analyze UFW firewall logs and report malicious IP addresse To prevent redundant reporting of the same IP address within a short period, the tool uses a temporary cache file to track previously reported IPs. This project was previously written in Bash, but it has been rewritten in [Node.js](https://nodejs.org). All my integration tools are currently written in Node, hence the change. -If you were using the old version, uninstall it as it will no longer be supported. +If you were using the old version, [uninstall it](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/tree/node.js?tab=readme-ov-file#%EF%B8%8F-remove-the-old-version) as it will no longer be supported. If you like this repository or find it useful, I would greatly appreciate it if you could give it a star ⭐. Thanks a lot! See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB) From 8e9d4fe7e2e7f8d709a73a7eeff1b630783dbb85 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:43:34 +0100 Subject: [PATCH 038/114] process?.send --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b6d69eb..4b99ea7 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/ ## 📥 Installation ```bash +sudo apt update && sudo apt upgrade cd ~ git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git cd UFW-AbuseIPDB-Reporter From 759413882a059894baca0c5e5d7a4d3bbb87bc49 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:44:33 +0100 Subject: [PATCH 039/114] process?.send --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4b99ea7..79da1b7 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/ ## 📋 Requirements -- [Node.js + npm](https://nodejs.org) -- [PM2](https://www.npmjs.com/package/pm2) -- [Git](https://git-scm.com) +1. [Node.js + npm](https://nodejs.org) +2. [PM2](https://www.npmjs.com/package/pm2) +3. [Git](https://git-scm.com) ## 📥 Installation From 0f447ee9ea9f5188c67cc57a4e91d02b6c9057ab Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:45:02 +0100 Subject: [PATCH 040/114] process?.send --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79da1b7..e13143b 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ pm2 logs ufw-abuseipdb ``` ### 📄 Example reports -#### 1 +#### 1️⃣ ``` Blocked by UFW on vserver1 [80/tcp] Source port: 23639 @@ -74,7 +74,7 @@ This report was generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter ``` -#### 2 +#### 2️⃣ ``` Blocked by UFW on vserver1 [30049/tcp]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter ``` From d4a25fcc5b4ad8e53f56abe054845e2483562625 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:45:19 +0100 Subject: [PATCH 041/114] process?.send --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e13143b..4e6c250 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ pm2 logs ufw-abuseipdb ### 📄 Example reports #### 1️⃣ -``` +```text Blocked by UFW on vserver1 [80/tcp] Source port: 23639 TTL: 247 @@ -75,7 +75,7 @@ https://github.com/sefinek/UFW-AbuseIPDB-Reporter ``` #### 2️⃣ -``` +```text Blocked by UFW on vserver1 [30049/tcp]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter ``` From e4c43b8b0c3a934a637be0a679710ef64014051b Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:46:09 +0100 Subject: [PATCH 042/114] Update --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index 28ed905..ac29dff 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,5 @@ +// Copyright 2024 © by Sefinek. All rights reserved. + const fs = require('node:fs'); const chokidar = require('chokidar'); const isLocalIP = require('./services/isLocalIP.js'); From 47c0879b8642f96a862830df2714b84e79ab28e4 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:50:49 +0100 Subject: [PATCH 043/114] Fixes --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index ac29dff..ae3e86b 100644 --- a/index.js +++ b/index.js @@ -121,8 +121,8 @@ const processLogLine = async line => { .on('change', path => { const stats = fs.statSync(path); if (stats.size < fileOffset) { - log(1, 'File truncated. Resetting offset...'); fileOffset = 0; + log(1, 'The file has been truncated, and the offset has been reset.'); } fs.createReadStream(path, { start: fileOffset, encoding: 'utf8' }).on('data', chunk => { From 4950af372aa980efd69598ee75b7b6bd0754b86f Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:53:14 +0100 Subject: [PATCH 044/114] Fixes --- services/serverIp.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/services/serverIp.js b/services/serverIp.js index b57a745..6a08bf0 100644 --- a/services/serverIp.js +++ b/services/serverIp.js @@ -17,10 +17,6 @@ const fetchIPAddress = async () => { } }; -if (process.env.NODE_ENV === 'production') { - (async () => fetchIPAddress())(); -} else { - address = '::ffff:127.0.0.1'; -} +(async () => fetchIPAddress())(); module.exports = () => address; \ No newline at end of file From e872525221ae5dd15dc24a2e458a6a16fd54ede6 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 01:54:16 +0100 Subject: [PATCH 045/114] Fixes --- pull.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 pull.txt diff --git a/pull.txt b/pull.txt new file mode 100644 index 0000000..54c50e3 --- /dev/null +++ b/pull.txt @@ -0,0 +1 @@ +git pull && pm2 restart ufw-abuseipdb && pm2 logs ufw-abuseipdb \ No newline at end of file From 2d57e66b0f067a9e8a584c3b77f1d573df765c9e Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 16:43:24 +0100 Subject: [PATCH 046/114] timestamp --- index.js | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/index.js b/index.js index ae3e86b..3372e0b 100644 --- a/index.js +++ b/index.js @@ -15,14 +15,16 @@ let fileOffset = 0; const reportToAbuseIPDb = async (logData, categories, comment) => { try { - const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ ip: logData.srcIp, categories, comment }), { - headers: { 'Key': ABUSEIPDB_API_KEY }, - }); + const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ + ip: logData.srcIp, + categories, + comment, + }), { headers: { 'Key': ABUSEIPDB_API_KEY } }); - log(0, `Reported ${logData.srcIp} (${logData.dpt}/${logData.proto}); Categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); + log(0, `Reported ${logData.srcIp} [${logData.dpt}/${logData.proto}]; ID: ${logData.id}; Categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); return true; } catch (err) { - log(2, `Failed to report ${logData.srcIp} (${logData.dpt}/${logData.proto}); ${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); + log(2, `Failed to report ${logData.srcIp} [${logData.dpt}/${logData.proto}]; ID: ${logData.id}; ${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); return false; } }; @@ -30,25 +32,29 @@ const reportToAbuseIPDb = async (logData, categories, comment) => { const processLogLine = async line => { if (!line.includes('[UFW BLOCK]')) return log(1, `Ignoring line: ${line}`); + const oldTime = line.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?/)?.[0]; + const timestampMatch = line.match(/\[(\d+\.\d+)\]/); + const newTime = timestampMatch ? parseFloat(timestampMatch[1]) : null; const logData = { - timestamp: line.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?/)?.[0] || null, - In: line.match(/IN=([\d.]+)/)?.[1] || null, - Out: line.match(/OUT=([\d.]+)/)?.[1] || null, - srcIp: line.match(/SRC=([\d.]+)/)?.[1] || null, - dstIp: line.match(/DST=([\d.]+)/)?.[1] || null, - res: line.match(/RES=(\S+)/)?.[1] || null, - tos: line.match(/TOS=(\S+)/)?.[1] || null, - prec: line.match(/PREC=(\S+)/)?.[1] || null, - ttl: line.match(/TTL=(\d+)/)?.[1] || null, - id: line.match(/ID=(\d+)/)?.[1] || null, - proto: line.match(/PROTO=(\S+)/)?.[1] || null, - spt: line.match(/SPT=(\d+)/)?.[1] || null, - dpt: line.match(/DPT=(\d+)/)?.[1] || null, - len: line.match(/LEN=(\d+)/)?.[1] || null, - urgp: line.match(/URGP=(\d+)/)?.[1] || null, - mac: line.match(/MAC=([\w:]+)/)?.[1] || null, - window: line.match(/WINDOW=(\d+)/)?.[1] || null, - syn: !!line.includes('SYN'), + timestampOld: oldTime || null, + timestampNew: newTime || null, + In: line.match(/IN=([\d.]+)/)?.[1] || null, + Out: line.match(/OUT=([\d.]+)/)?.[1] || null, + srcIp: line.match(/SRC=([\d.]+)/)?.[1] || null, + dstIp: line.match(/DST=([\d.]+)/)?.[1] || null, + res: line.match(/RES=(\S+)/)?.[1] || null, + tos: line.match(/TOS=(\S+)/)?.[1] || null, + prec: line.match(/PREC=(\S+)/)?.[1] || null, + ttl: line.match(/TTL=(\d+)/)?.[1] || null, + id: line.match(/ID=(\d+)/)?.[1] || null, + proto: line.match(/PROTO=(\S+)/)?.[1] || null, + spt: line.match(/SPT=(\d+)/)?.[1] || null, + dpt: line.match(/DPT=(\d+)/)?.[1] || null, + len: line.match(/LEN=(\d+)/)?.[1] || null, + urgp: line.match(/URGP=(\d+)/)?.[1] || null, + mac: line.match(/MAC=([\w:]+)/)?.[1] || null, + window: line.match(/WINDOW=(\d+)/)?.[1] || null, + syn: !!line.includes('SYN'), }; const { srcIp, proto, dpt } = logData; From ecbe7bd861d3ad312189379340134e65868a320c Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:07:20 +0100 Subject: [PATCH 047/114] Create install.sh (beta) --- install.sh | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 install.sh diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..f11af69 --- /dev/null +++ b/install.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +# Function to check and install missing dependencies +check_dependencies() { + local dependencies=(curl node git) + local missing=() + + for dependency in "${dependencies[@]}"; do + if ! command -v $dependency &> /dev/null; then + missing+=("$dependency") + fi + done + + if [[ ${#missing[@]} -gt 0 ]]; then + echo "🚨 Missing dependencies: ${missing[*]}" + for dep in "${missing[@]}"; do + read -p "📦 Do you want to install $dep? [Yes/No]: " answer + case $answer in + [Yy]*|[Yy]es ) + case $dep in + curl ) sudo apt-get install -y curl ;; + node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && sudo -E bash nodesource_setup.sh && sudo apt-get install -y nodejs ;; + git ) sudo add-apt-repository ppa:git-core/ppa && sudo apt-get update && sudo apt-get -y install git ;; + esac + ;; + [Nn]*|[Nn]o ) + echo "❌ Cannot proceed without $dep. Exiting." + exit 1 + ;; + * ) + echo "❌ Invalid input. Exiting." + exit 1 + ;; + esac + done + else + echo "✅ All dependencies are installed." + fi +} + +# Check dependencies before proceeding +check_dependencies + +# Function to validate AbuseIPDB API key +validate_token() { + local api_key=$1 + local response + + response=$(curl -s -o /dev/null -w "%{http_code}" -H "Key: $api_key" https://api.abuseipdb.com/api/v2/check?ipAddress=8.8.8.8) + + if [[ $response -eq 200 ]]; then + return 0 + else + echo "🚨 Invalid token. Please try again." + return 1 + fi +} + +# Check for UFW log file +if [[ ! -f /var/log/ufw.log ]]; then + read -p "🔍 /var/log/ufw.log not found. Please enter the path to your log file: " ufw_log_path + if [[ -f $ufw_log_path ]]; then + echo "✅ Log file found at $ufw_log_path." + else + echo "❌ Provided log file path does not exist. Exiting." + exit 1 + fi +else + ufw_log_path="/var/log/ufw.log" + echo "✅ /var/log/ufw.log exists." +fi + +# Prompt for AbuseIPDB API token +while true; do + read -p "🔑 Please enter your AbuseIPDB API token: " api_token + if validate_token "$api_token"; then + break + fi + continue +done + +# Prompt for server ID +read -p "🖥️ Enter your Server ID (leave blank for null): " server_id +if [[ -z $server_id ]]; then + server_id=null +fi + +# Prompt for system update and upgrade +read -p "🛠️ Do you want to update and upgrade the system (apt upgrade)? [Yes/No]: " answer +case $answer in + [Yy]*|[Yy]es ) + echo "🔧 Updating and upgrading the system..." + sudo apt-get update && sudo apt-get upgrade -y + ;; + [Nn]*|[Nn]o ) + echo "⏩ Skipping system update and upgrade..." + ;; + * ) + echo "❌ Invalid input. Exiting..." + exit 1 + ;; +esac + +# Clone repository +cd /home +if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then + echo "📂 Cloning the UFW-AbuseIPDB-Reporter repository..." + git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js +else + echo "📂 The UFW-AbuseIPDB-Reporter repository already exists. Pulling latest changes..." + cd UFW-AbuseIPDB-Reporter + git pull +fi + +# Install npm dependencies +echo "📦 Installing npm dependencies..." +npm install --silent + +# Copy configuration file +echo "📑 Copying default.config.js to config.js..." +cp default.config.js config.js + +# Update config.js with API token, Server ID, and UFW log path +config_file="config.js" +if [[ -f $config_file ]]; then + echo "🔧 Updating $PWD/$config_file..." + sed -i "s|UFW_FILE: .*|UFW_FILE: '$ufw_log_path',|" $config_file + sed -i "s|SERVER_ID: .*|SERVER_ID: '$server_id',|" $config_file + sed -i "s|ABUSEIPDB_API_KEY: .*|ABUSEIPDB_API_KEY: '$api_token',|" $config_file +else + echo "❌ $config_file not found. Make sure the repository was cloned and initialized correctly." + exit 1 +fi + +# Change permissions for UFW log file +echo "🔒 Changing permissions for $ufw_log_path..." +sudo chmod 644 "$ufw_log_path" + +# Uninstall corepack +echo "🗑️ Uninstalling corepack..." +npm uninstall corepack -g --silent + +# Install pm2 +echo "📦 Installing pm2..." +npm install pm2 -g --silent + +# Create logs directory +echo "📂 Creating /var/log/ufw-abuseipdb directory..." +sudo mkdir -p /var/log/ufw-abuseipdb +sudo chown "$USER":"$USER" /var/log/ufw-abuseipdb -R + +# Configure pm2 +echo "⚙️ Configuring pm2..." +pm2 start +pm2 startup + +# Execute the command generated by pm2 startup +echo "🔧 Complete pm2 startup configuration:" +sudo env PATH="$PATH":/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u "$USER" --hp /home/"$USER" + +pm2 save + +echo "🎉 Installation and configuration completed!" + + +# Final +echo -e "\n=================================== Installation Summary ===================================" +echo "🔑 API Token : $api_token" +echo "🖥️ Server ID : ${server_id:-null}" +echo "📂 Script : $PWD" +echo "⚙️ Config File : $PWD/config.js" + +echo -e "\n=================================== Support ===================================" +echo "📩 Email : contact@sefinek.net" +echo "🔵 Discord : https://discord.gg/RVH8UXgmzs" +echo "😺 GitHub Issues : https://github.com/sefinek/UFW-AbuseIPDB-Reporter/issues" From 87303c9ab04a4a17bcd7a556d372d6d537289f15 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:07:32 +0100 Subject: [PATCH 048/114] Update README.md --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e6c250..9c59fe4 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,24 @@ See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/ ## 📥 Installation + +### Node.js (Ubuntu & Debian) ```bash -sudo apt update && sudo apt upgrade +sudo apt-get install -y curl +curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh +sudo -E bash nodesource_setup.sh +sudo apt-get install -y nodejs +``` + +### Git +```bash +sudo add-apt-repository ppa:git-core/ppa +sudo apt-get update && sudo apt-get -y install git +``` + +### Script +```bash +sudo apt-get update && sudo apt-get upgrade cd ~ git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git cd UFW-AbuseIPDB-Reporter From d9117d1711ca7dc96c800546f55d45706f08fcb5 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:16:15 +0100 Subject: [PATCH 049/114] =?UTF-8?q?Add=20`=E2=9D=8C=20This=20script=20must?= =?UTF-8?q?=20be=20run=20as=20root.`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install.sh | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/install.sh b/install.sh index f11af69..d16f619 100644 --- a/install.sh +++ b/install.sh @@ -1,5 +1,11 @@ #!/bin/bash +# Ensure the script is run as root +if [ "$EUID" -ne 0 ]; then + echo "❌ This script must be run as root. Exiting..." + exit 1 +fi + # Function to check and install missing dependencies check_dependencies() { local dependencies=(curl node git) @@ -18,9 +24,9 @@ check_dependencies() { case $answer in [Yy]*|[Yy]es ) case $dep in - curl ) sudo apt-get install -y curl ;; - node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && sudo -E bash nodesource_setup.sh && sudo apt-get install -y nodejs ;; - git ) sudo add-apt-repository ppa:git-core/ppa && sudo apt-get update && sudo apt-get -y install git ;; + curl ) apt-get install -y curl ;; + node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && bash nodesource_setup.sh && apt-get install -y nodejs && rm nodesource_setup.sh -f ;; + git ) add-apt-repository ppa:git-core/ppa && apt-get update && apt-get -y install git ;; esac ;; [Nn]*|[Nn]o ) @@ -90,7 +96,7 @@ read -p "🛠️ Do you want to update and upgrade the system (apt upgrade)? [Ye case $answer in [Yy]*|[Yy]es ) echo "🔧 Updating and upgrading the system..." - sudo apt-get update && sudo apt-get upgrade -y + apt-get update && apt-get upgrade -y ;; [Nn]*|[Nn]o ) echo "⏩ Skipping system update and upgrade..." @@ -134,7 +140,7 @@ fi # Change permissions for UFW log file echo "🔒 Changing permissions for $ufw_log_path..." -sudo chmod 644 "$ufw_log_path" +chmod 644 "$ufw_log_path" # Uninstall corepack echo "🗑️ Uninstalling corepack..." @@ -146,8 +152,8 @@ npm install pm2 -g --silent # Create logs directory echo "📂 Creating /var/log/ufw-abuseipdb directory..." -sudo mkdir -p /var/log/ufw-abuseipdb -sudo chown "$USER":"$USER" /var/log/ufw-abuseipdb -R +mkdir -p /var/log/ufw-abuseipdb +chown "$USER":"$USER" /var/log/ufw-abuseipdb -R # Configure pm2 echo "⚙️ Configuring pm2..." @@ -164,13 +170,13 @@ echo "🎉 Installation and configuration completed!" # Final -echo -e "\n=================================== Installation Summary ===================================" +echo -e "\n====================================== Summary ======================================" echo "🔑 API Token : $api_token" echo "🖥️ Server ID : ${server_id:-null}" echo "📂 Script : $PWD" echo "⚙️ Config File : $PWD/config.js" -echo -e "\n=================================== Support ===================================" +echo -e "\n====================================== Support ======================================" echo "📩 Email : contact@sefinek.net" echo "🔵 Discord : https://discord.gg/RVH8UXgmzs" echo "😺 GitHub Issues : https://github.com/sefinek/UFW-AbuseIPDB-Reporter/issues" From 933af43af4b94a167685ba215d02dc83ec1c0112 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:25:38 +0100 Subject: [PATCH 050/114] Quality fixes for install.sh --- install.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/install.sh b/install.sh index d16f619..7f2da37 100644 --- a/install.sh +++ b/install.sh @@ -12,7 +12,7 @@ check_dependencies() { local missing=() for dependency in "${dependencies[@]}"; do - if ! command -v $dependency &> /dev/null; then + if ! command -v "$dependency" &> /dev/null; then missing+=("$dependency") fi done @@ -20,12 +20,12 @@ check_dependencies() { if [[ ${#missing[@]} -gt 0 ]]; then echo "🚨 Missing dependencies: ${missing[*]}" for dep in "${missing[@]}"; do - read -p "📦 Do you want to install $dep? [Yes/No]: " answer + read -r -p "📦 Do you want to install $dep? [Yes/No]: " answer case $answer in [Yy]*|[Yy]es ) case $dep in curl ) apt-get install -y curl ;; - node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && bash nodesource_setup.sh && apt-get install -y nodejs && rm nodesource_setup.sh -f ;; + node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && bash nodesource_setup.sh && apt-get install -y nodejs && rm -f nodesource_setup.sh ;; git ) add-apt-repository ppa:git-core/ppa && apt-get update && apt-get -y install git ;; esac ;; @@ -64,7 +64,7 @@ validate_token() { # Check for UFW log file if [[ ! -f /var/log/ufw.log ]]; then - read -p "🔍 /var/log/ufw.log not found. Please enter the path to your log file: " ufw_log_path + read -r -p "🔍 /var/log/ufw.log not found. Please enter the path to your log file: " ufw_log_path if [[ -f $ufw_log_path ]]; then echo "✅ Log file found at $ufw_log_path." else @@ -78,7 +78,7 @@ fi # Prompt for AbuseIPDB API token while true; do - read -p "🔑 Please enter your AbuseIPDB API token: " api_token + read -r -p "🔑 Please enter your AbuseIPDB API token: " api_token if validate_token "$api_token"; then break fi @@ -86,13 +86,13 @@ while true; do done # Prompt for server ID -read -p "🖥️ Enter your Server ID (leave blank for null): " server_id +read -r -p "🖥️ Enter your Server ID (leave blank for null): " server_id if [[ -z $server_id ]]; then server_id=null fi # Prompt for system update and upgrade -read -p "🛠️ Do you want to update and upgrade the system (apt upgrade)? [Yes/No]: " answer +read -r -p "🛠️ Do you want to update and upgrade the system (apt upgrade)? [Yes/No]: " answer case $answer in [Yy]*|[Yy]es ) echo "🔧 Updating and upgrading the system..." @@ -108,13 +108,13 @@ case $answer in esac # Clone repository -cd /home +cd /home || exit if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then echo "📂 Cloning the UFW-AbuseIPDB-Reporter repository..." git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js else echo "📂 The UFW-AbuseIPDB-Reporter repository already exists. Pulling latest changes..." - cd UFW-AbuseIPDB-Reporter + cd UFW-AbuseIPDB-Reporter || exit git pull fi @@ -166,7 +166,7 @@ sudo env PATH="$PATH":/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd pm2 save -echo "🎉 Installation and configuration completed!" +echo -e "\n\n🎉 Installation and configuration completed!" # Final From d34ce47730f914764ad254b905b1351f30ddf78f Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:25:44 +0100 Subject: [PATCH 051/114] Quality fixes for install.sh --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 7f2da37..a08b450 100644 --- a/install.sh +++ b/install.sh @@ -166,10 +166,10 @@ sudo env PATH="$PATH":/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd pm2 save -echo -e "\n\n🎉 Installation and configuration completed!" - # Final +echo -e "\n\n🎉 Installation and configuration completed!" + echo -e "\n====================================== Summary ======================================" echo "🔑 API Token : $api_token" echo "🖥️ Server ID : ${server_id:-null}" From 46e8775bac52e9844801c5360f2164324c7abf1b Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:36:56 +0100 Subject: [PATCH 052/114] Update `Prompt for server ID` --- install.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/install.sh b/install.sh index a08b450..2dbab53 100644 --- a/install.sh +++ b/install.sh @@ -86,10 +86,17 @@ while true; do done # Prompt for server ID -read -r -p "🖥️ Enter your Server ID (leave blank for null): " server_id -if [[ -z $server_id ]]; then - server_id=null -fi +while true; do + read -r -p "🖥️ Enter the server ID, leave blank if you do not wish to provide one (e.g., homeserver1): " server_id + if [[ -z $server_id ]]; then + server_id=null + break + elif [[ $server_id =~ ^[A-Za-z0-9]{1,16}$ ]]; then + break + else + echo "❌ It must be 1-16 characters long, contain only letters and numbers, and have no spaces or special characters." + fi +done # Prompt for system update and upgrade read -r -p "🛠️ Do you want to update and upgrade the system (apt upgrade)? [Yes/No]: " answer From 38116ff9f89287fdc855d8225a416b602bb69609 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:45:18 +0100 Subject: [PATCH 053/114] #!/usr/bin/env bash --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 2dbab53..4e288f8 100644 --- a/install.sh +++ b/install.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Ensure the script is run as root if [ "$EUID" -ne 0 ]; then From bd25f9d93528f72899f8b2ed096686cace5cea85 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:46:07 +0100 Subject: [PATCH 054/114] Update install.sh --- install.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/install.sh b/install.sh index 4e288f8..2e808c3 100644 --- a/install.sh +++ b/install.sh @@ -1,11 +1,5 @@ #!/usr/bin/env bash -# Ensure the script is run as root -if [ "$EUID" -ne 0 ]; then - echo "❌ This script must be run as root. Exiting..." - exit 1 -fi - # Function to check and install missing dependencies check_dependencies() { local dependencies=(curl node git) From fd0e89f056ec04dcc31b41ef5f45b6ff6bd280e5 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 18:58:54 +0100 Subject: [PATCH 055/114] Update install.sh --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 2e808c3..1467ded 100644 --- a/install.sh +++ b/install.sh @@ -109,13 +109,13 @@ case $answer in esac # Clone repository -cd /home || exit +cd ~ || exit if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then echo "📂 Cloning the UFW-AbuseIPDB-Reporter repository..." git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js else echo "📂 The UFW-AbuseIPDB-Reporter repository already exists. Pulling latest changes..." - cd UFW-AbuseIPDB-Reporter || exit + cd ~/UFW-AbuseIPDB-Reporter || exit git pull fi From 69865957cbab0a7c25626617c60997d0d9d5d435 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:01:26 +0100 Subject: [PATCH 056/114] Update install.sh --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index 1467ded..70643b5 100644 --- a/install.sh +++ b/install.sh @@ -169,6 +169,7 @@ pm2 save # Final +pm2 status echo -e "\n\n🎉 Installation and configuration completed!" echo -e "\n====================================== Summary ======================================" From b84737569fde56f447620840ef246e6b2338b034 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:06:04 +0100 Subject: [PATCH 057/114] Update install.sh --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 70643b5..99526fe 100644 --- a/install.sh +++ b/install.sh @@ -109,13 +109,13 @@ case $answer in esac # Clone repository -cd ~ || exit +cd ~ || return if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then echo "📂 Cloning the UFW-AbuseIPDB-Reporter repository..." git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js else echo "📂 The UFW-AbuseIPDB-Reporter repository already exists. Pulling latest changes..." - cd ~/UFW-AbuseIPDB-Reporter || exit + cd UFW-AbuseIPDB-Reporter || return git pull fi From f863f6b25b5340916e9288235fdf450874a84914 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:08:15 +0100 Subject: [PATCH 058/114] Update install.sh --- install.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/install.sh b/install.sh index 99526fe..24f95d3 100644 --- a/install.sh +++ b/install.sh @@ -109,14 +109,23 @@ case $answer in esac # Clone repository -cd ~ || return +if [ -d "/home" ]; then + mkdir -p /home/new_directory + echo "✅ '/home/new_directory' has been created." +else + echo "❌ '/home' directory does not exist. Exiting..." + exit 1 +fi + +cd /home || { echo "❌ Failed to change directory to '/home'. Exiting..."; exit 1; } + if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then echo "📂 Cloning the UFW-AbuseIPDB-Reporter repository..." - git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js + git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js || { echo "❌ Failed to clone the repository. Exiting..."; exit 1; } else echo "📂 The UFW-AbuseIPDB-Reporter repository already exists. Pulling latest changes..." - cd UFW-AbuseIPDB-Reporter || return - git pull + cd UFW-AbuseIPDB-Reporter || { echo "❌ Failed to change directory to 'UFW-AbuseIPDB-Reporter'. Exiting..."; exit 1; } + git pull || { echo "❌ Failed to pull the latest changes. Exiting..."; exit 1; } fi # Install npm dependencies From 3bcac789eb4d2616dd390cb47c5638c4bb80ab3e Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:08:49 +0100 Subject: [PATCH 059/114] Update install.sh --- install.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index 24f95d3..05d2b72 100644 --- a/install.sh +++ b/install.sh @@ -111,7 +111,7 @@ esac # Clone repository if [ -d "/home" ]; then mkdir -p /home/new_directory - echo "✅ '/home/new_directory' has been created." + echo "📂 '/home/new_directory' has been created." else echo "❌ '/home' directory does not exist. Exiting..." exit 1 @@ -120,10 +120,10 @@ fi cd /home || { echo "❌ Failed to change directory to '/home'. Exiting..."; exit 1; } if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then - echo "📂 Cloning the UFW-AbuseIPDB-Reporter repository..." + echo "📥 Cloning the UFW-AbuseIPDB-Reporter repository..." git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js || { echo "❌ Failed to clone the repository. Exiting..."; exit 1; } else - echo "📂 The UFW-AbuseIPDB-Reporter repository already exists. Pulling latest changes..." + echo "✨ The UFW-AbuseIPDB-Reporter repository already exists! Pulling latest changes..." cd UFW-AbuseIPDB-Reporter || { echo "❌ Failed to change directory to 'UFW-AbuseIPDB-Reporter'. Exiting..."; exit 1; } git pull || { echo "❌ Failed to pull the latest changes. Exiting..."; exit 1; } fi From 4fbd8f2c766aa824ebd54cb3b236e9c57be4d9ce Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:10:07 +0100 Subject: [PATCH 060/114] Update install.sh --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 05d2b72..c52beaa 100644 --- a/install.sh +++ b/install.sh @@ -103,7 +103,7 @@ case $answer in echo "⏩ Skipping system update and upgrade..." ;; * ) - echo "❌ Invalid input. Exiting..." + echo "❌ Confused. Invalid input. Expected Yes/no or Y/n." exit 1 ;; esac From d7af3a137b4dd3e1323e1a3ed44e4e2bd2d3b017 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:11:49 +0100 Subject: [PATCH 061/114] Update install.sh --- install.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index c52beaa..3d34bfd 100644 --- a/install.sh +++ b/install.sh @@ -157,7 +157,7 @@ echo "🗑️ Uninstalling corepack..." npm uninstall corepack -g --silent # Install pm2 -echo "📦 Installing pm2..." +echo "📦 Installing PM2..." npm install pm2 -g --silent # Create logs directory @@ -166,7 +166,7 @@ mkdir -p /var/log/ufw-abuseipdb chown "$USER":"$USER" /var/log/ufw-abuseipdb -R # Configure pm2 -echo "⚙️ Configuring pm2..." +echo "⚙️ Configuring PM2..." pm2 start pm2 startup @@ -178,7 +178,9 @@ pm2 save # Final +echo "🌌 Checking PM2 status..." pm2 status + echo -e "\n\n🎉 Installation and configuration completed!" echo -e "\n====================================== Summary ======================================" From c6860491544e6c6db2cc022fc3649b6f4f54a2ab Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:15:49 +0100 Subject: [PATCH 062/114] Update install.sh --- install.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/install.sh b/install.sh index 3d34bfd..8b3458a 100644 --- a/install.sh +++ b/install.sh @@ -34,7 +34,7 @@ check_dependencies() { esac done else - echo "✅ All dependencies are installed." + echo "✅ All dependencies are installed!" fi } @@ -97,7 +97,7 @@ read -r -p "🛠️ Do you want to update and upgrade the system (apt upgrade)? case $answer in [Yy]*|[Yy]es ) echo "🔧 Updating and upgrading the system..." - apt-get update && apt-get upgrade -y + apt-get update > /dev/null 2>&1 && apt-get upgrade ;; [Nn]*|[Nn]o ) echo "⏩ Skipping system update and upgrade..." @@ -123,11 +123,13 @@ if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then echo "📥 Cloning the UFW-AbuseIPDB-Reporter repository..." git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js || { echo "❌ Failed to clone the repository. Exiting..."; exit 1; } else - echo "✨ The UFW-AbuseIPDB-Reporter repository already exists! Pulling latest changes..." - cd UFW-AbuseIPDB-Reporter || { echo "❌ Failed to change directory to 'UFW-AbuseIPDB-Reporter'. Exiting..."; exit 1; } - git pull || { echo "❌ Failed to pull the latest changes. Exiting..."; exit 1; } + echo "✨ The UFW-AbuseIPDB-Reporter repository already exists!" fi +echo "📥 Pulling latest changes..." +cd UFW-AbuseIPDB-Reporter || { echo "❌ Failed to change directory to 'UFW-AbuseIPDB-Reporter'. Exiting..."; exit 1; } +git pull || { echo "❌ Failed to pull the latest changes. Exiting..."; exit 1; } + # Install npm dependencies echo "📦 Installing npm dependencies..." npm install --silent From 36e9cd00c70be3874f27a77f1ab4683b5836c296 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:17:16 +0100 Subject: [PATCH 063/114] Update install.sh --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 8b3458a..efd432c 100644 --- a/install.sh +++ b/install.sh @@ -180,10 +180,10 @@ pm2 save # Final -echo "🌌 Checking PM2 status..." +echo -e "\n\n🌌 Checking PM2 status..." pm2 status -echo -e "\n\n🎉 Installation and configuration completed!" +echo -e "\n🎉 Installation and configuration completed!" echo -e "\n====================================== Summary ======================================" echo "🔑 API Token : $api_token" From e767f9ae74782ce719eccaef2b81c52e05dc5db4 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:18:13 +0100 Subject: [PATCH 064/114] Update README.md --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c59fe4..095973b 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,19 @@ See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/ ## 📥 Installation -### Node.js (Ubuntu & Debian) +### Automatic (Easy & recommenced) +#### curl +```bash +cd /tmp && curl -s -o /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && sudo bash install.sh && rm install.sh +``` + +#### wget +```bash +cd /tmp && wget -q -O /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && sudo bash install.sh && rm install.sh +``` + +### Manually +#### Node.js (Ubuntu & Debian) ```bash sudo apt-get install -y curl curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh @@ -28,13 +40,13 @@ sudo -E bash nodesource_setup.sh sudo apt-get install -y nodejs ``` -### Git +#### Git ```bash sudo add-apt-repository ppa:git-core/ppa sudo apt-get update && sudo apt-get -y install git ``` -### Script +#### Script ```bash sudo apt-get update && sudo apt-get upgrade cd ~ From 021d653dad2915a7121538dd531e7cc5c6d8d8b2 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Wed, 25 Dec 2024 19:27:11 +0100 Subject: [PATCH 065/114] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 095973b..95608ad 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ pm2 startup pm2 save ``` -## 🗑️ Remove the old version +## 🗑️ Uninstall the deprecated version if you have it ```bash sudo systemctl stop abuseipdb-ufw.service sudo systemctl disable abuseipdb-ufw.service From 15871637aa7987920c09caeffe24b150746fdc77 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 02:44:17 +0100 Subject: [PATCH 066/114] Small fixes --- install.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/install.sh b/install.sh index efd432c..bcff0cb 100644 --- a/install.sh +++ b/install.sh @@ -24,17 +24,17 @@ check_dependencies() { esac ;; [Nn]*|[Nn]o ) - echo "❌ Cannot proceed without $dep. Exiting." + echo "❌ Cannot proceed without $dep. Exiting..." exit 1 ;; * ) - echo "❌ Invalid input. Exiting." + echo "❌ Invalid input. Exiting..." exit 1 ;; esac done else - echo "✅ All dependencies are installed!" + echo "✅ All dependencies are installed" fi } @@ -62,12 +62,12 @@ if [[ ! -f /var/log/ufw.log ]]; then if [[ -f $ufw_log_path ]]; then echo "✅ Log file found at $ufw_log_path." else - echo "❌ Provided log file path does not exist. Exiting." + echo "❌ Provided log file path does not exist. Exiting..." exit 1 fi else ufw_log_path="/var/log/ufw.log" - echo "✅ /var/log/ufw.log exists." + echo "✅ /var/log/ufw.log exists" fi # Prompt for AbuseIPDB API token @@ -81,7 +81,7 @@ done # Prompt for server ID while true; do - read -r -p "🖥️ Enter the server ID, leave blank if you do not wish to provide one (e.g., homeserver1): " server_id + read -r -p "🖥️ Enter the server ID. Leave blank if you do not wish to provide one (e.g., homeserver1): " server_id if [[ -z $server_id ]]; then server_id=null break @@ -93,7 +93,7 @@ while true; do done # Prompt for system update and upgrade -read -r -p "🛠️ Do you want to update and upgrade the system (apt upgrade)? [Yes/No]: " answer +read -r -p "🛠️ Do you want the script to run apt update and apt upgrade for you? [Yes/No]: " answer case $answer in [Yy]*|[Yy]es ) echo "🔧 Updating and upgrading the system..." From f01c29675072137f54dd65667ae66422ff7e23fe Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 02:45:52 +0100 Subject: [PATCH 067/114] Small fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index bcff0cb..b38bfa7 100644 --- a/install.sh +++ b/install.sh @@ -111,7 +111,7 @@ esac # Clone repository if [ -d "/home" ]; then mkdir -p /home/new_directory - echo "📂 '/home/new_directory' has been created." + echo "📂 '/home/new_directory' has been created" else echo "❌ '/home' directory does not exist. Exiting..." exit 1 From 4f16dfda77b7145bbba96fb65272b3606c9d8966 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 02:50:12 +0100 Subject: [PATCH 068/114] Small fixes --- install.sh | 68 +++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/install.sh b/install.sh index b38bfa7..2917b53 100644 --- a/install.sh +++ b/install.sh @@ -1,5 +1,18 @@ #!/usr/bin/env bash +# Function to prompt for a Yes/no answer +yes_no_prompt() { + local prompt="$1" + while true; do + read -r -p "$prompt [Yes/no]: " answer + case $answer in + [Yy]*|[Yy]es ) return 0 ;; # Return 0 for Yes + [Nn]*|[Nn]o ) return 1 ;; # Return 1 for No + * ) echo "❌ Invalid input. Please answer Yes/no or Y/n." ;; + esac + done +} + # Function to check and install missing dependencies check_dependencies() { local dependencies=(curl node git) @@ -8,30 +21,29 @@ check_dependencies() { for dependency in "${dependencies[@]}"; do if ! command -v "$dependency" &> /dev/null; then missing+=("$dependency") + else + echo "✅ $dependency is installed ($(command -v "$dependency"))" + if $dependency --version &> /dev/null; then + $dependency --version + else + echo "ℹ️ Version information for $dependency is unavailable" + fi fi done if [[ ${#missing[@]} -gt 0 ]]; then echo "🚨 Missing dependencies: ${missing[*]}" for dep in "${missing[@]}"; do - read -r -p "📦 Do you want to install $dep? [Yes/No]: " answer - case $answer in - [Yy]*|[Yy]es ) - case $dep in - curl ) apt-get install -y curl ;; - node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && bash nodesource_setup.sh && apt-get install -y nodejs && rm -f nodesource_setup.sh ;; - git ) add-apt-repository ppa:git-core/ppa && apt-get update && apt-get -y install git ;; - esac - ;; - [Nn]*|[Nn]o ) - echo "❌ Cannot proceed without $dep. Exiting..." - exit 1 - ;; - * ) - echo "❌ Invalid input. Exiting..." - exit 1 - ;; - esac + if yes_no_prompt "📦 Do you want to install $dep?"; then + case $dep in + curl ) apt-get install -y curl ;; + node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && bash nodesource_setup.sh && apt-get install -y nodejs && rm -f nodesource_setup.sh ;; + git ) add-apt-repository ppa:git-core/ppa && apt-get update && apt-get -y install git ;; + esac + else + echo "❌ Cannot proceed without $dep. Exiting..." + exit 1 + fi done else echo "✅ All dependencies are installed" @@ -93,20 +105,12 @@ while true; do done # Prompt for system update and upgrade -read -r -p "🛠️ Do you want the script to run apt update and apt upgrade for you? [Yes/No]: " answer -case $answer in - [Yy]*|[Yy]es ) - echo "🔧 Updating and upgrading the system..." - apt-get update > /dev/null 2>&1 && apt-get upgrade - ;; - [Nn]*|[Nn]o ) - echo "⏩ Skipping system update and upgrade..." - ;; - * ) - echo "❌ Confused. Invalid input. Expected Yes/no or Y/n." - exit 1 - ;; -esac +if yes_no_prompt "🛠️ Do you want the script to run apt update and apt upgrade for you?"; then + echo "🔧 Updating and upgrading the system..." + apt-get update > /dev/null 2>&1 && apt-get upgrade +else + echo "⏩ Skipping system update and upgrade..." +fi # Clone repository if [ -d "/home" ]; then From edb5a9d8fed8e2ec4fc9bccac382491e67640d87 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:02:55 +0100 Subject: [PATCH 069/114] Small fixes --- README.md | 38 ++++++++++++++++++++++++-------------- default.config.js | 4 ++-- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 95608ad..189bc64 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,17 @@ # 🛡️ UFW AbuseIPDB Reporter -A utility designed to analyze UFW firewall logs and report malicious IP addresses to the [AbuseIPDB](https://www.abuseipdb.com) database. -To prevent redundant reporting of the same IP address within a short period, the tool uses a temporary cache file to track previously reported IPs. +A utility designed to analyze UFW logs and report IP addresses blocked by the firewall to the [AbuseIPDB](https://www.abuseipdb.com) database. +To prevent excessive reporting of the same IP address within a short period, the tool uses a temporary cache file to track previously reported IP addresses. -This project was previously written in Bash, but it has been rewritten in [Node.js](https://nodejs.org). All my integration tools are currently written in Node, hence the change. -If you were using the old version, [uninstall it](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/tree/node.js?tab=readme-ov-file#%EF%B8%8F-remove-the-old-version) as it will no longer be supported. +This project was previously written in Bash but has been rewritten in [Node.js](https://nodejs.org). All my integration tools are now written in Node, hence this change. +If you were using the old version, please [uninstall it](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/tree/node.js?tab=readme-ov-file#%EF%B8%8F-remove-the-old-version) as it will no longer be supported. -If you like this repository or find it useful, I would greatly appreciate it if you could give it a star ⭐. Thanks a lot! -See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB) +If you like this repository or find it useful, I’d greatly appreciate it if you could give it a star ⭐. Many thanks! +Also, check this out: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB) -> [!IMPORTANT] -> If you'd like to make changes to any files in this repository, please start by creating a [public fork](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/fork). +> [!IMPORTANT] +> - If you'd like to make changes to any files in this repository, please start by creating a [public fork](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/fork). +> +> - According to AbuseIPDB's policy, UDP traffic should not be reported! ## 📋 Requirements @@ -18,6 +20,14 @@ See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/ 3. [Git](https://git-scm.com) +## ✅ Features +1. A `config.js` file enabling easy configuration. +2. A simple installer allowing quick integration deployment. +3. Integration with Discord Webhooks (coming soon): + - Alerts in case of script errors + - Daily summaries of reported IP addresses + + ## 📥 Installation ### Automatic (Easy & recommenced) @@ -67,10 +77,10 @@ pm2 startup pm2 save ``` + ## 🗑️ Uninstall the deprecated version if you have it ```bash -sudo systemctl stop abuseipdb-ufw.service -sudo systemctl disable abuseipdb-ufw.service +sudo systemctl stop abuseipdb-ufw.service && sudo systemctl disable abuseipdb-ufw.service sudo rm /etc/systemd/system/abuseipdb-ufw.service sudo systemctl daemon-reload sudo rm -r /usr/local/bin/UFW-AbuseIPDB-Reporter @@ -92,7 +102,7 @@ pm2 logs ufw-abuseipdb ### 📄 Example reports #### 1️⃣ ```text -Blocked by UFW on vserver1 [80/tcp] +Blocked by UFW on homeserver01 [80/tcp] Source port: 23639 TTL: 247 Packet length: 40 @@ -104,7 +114,7 @@ https://github.com/sefinek/UFW-AbuseIPDB-Reporter #### 2️⃣ ```text -Blocked by UFW on vserver1 [30049/tcp]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter +Blocked by UFW on homeserver01 [30049/tcp]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter ``` @@ -112,5 +122,5 @@ Blocked by UFW on vserver1 [30049/tcp]. Generated by: https://github.com/sefinek If you want to contribute to the development of this project, feel free to create a new [Pull request](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/pulls). I will definitely appreciate it! -## 🔑 GPL-3.0 License -Copyright 2024 © by [Sefinek](https://sefinek.net). All rights reserved. See the [LICENSE](LICENSE) file for more information. \ No newline at end of file +## 🔑 [GPL-3.0 License](LICENSE) +Copyright 2024-2025 © by [Sefinek](https://sefinek.net). All rights reserved. \ No newline at end of file diff --git a/default.config.js b/default.config.js index af73952..3baf9eb 100644 --- a/default.config.js +++ b/default.config.js @@ -2,7 +2,7 @@ exports.MAIN = { // Server UFW_FILE: '/var/log/ufw.log', CACHE_FILE: '/tmp/ufw-abuseipdb-reporter.cache', - SERVER_ID: null, // The server name that will be visible in the reports. If you don't want to define it, leave the value as null. + SERVER_ID: null, // The server name that will be visible in the reports (e.g. 'homeserver01'). If you don't want to define it, leave the value as null. // Reporting ABUSEIPDB_API_KEY: '', @@ -50,7 +50,7 @@ https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this // Alternative version: // exports.REPORT_COMMENT = ({ timestamp, In, Out, srcIp, dstIp, res, tos, prec, ttl, id, proto, spt, dpt, len, urgp, mac, window, syn }, fullLog, serverName) => -// `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙 +// `Blocked by UFW ${serverName ? `on ${serverName} ` : ''}[${dpt}/${proto?.toLowerCase()}]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // See: https://www.abuseipdb.com/categories From 56ef595d30c245e5c24356136ffdb17e8bfdcad2 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:03:14 +0100 Subject: [PATCH 070/114] Small fixes --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 189bc64..82a4e2a 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,8 @@ If you were using the old version, please [uninstall it](https://github.com/sefi If you like this repository or find it useful, I’d greatly appreciate it if you could give it a star ⭐. Many thanks! Also, check this out: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB) -> [!IMPORTANT] +> [!IMPORTANT] > - If you'd like to make changes to any files in this repository, please start by creating a [public fork](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/fork). -> > - According to AbuseIPDB's policy, UDP traffic should not be reported! From 3f20c148a36edb4beecb969f8ccb0ef0a4463d3a Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:04:04 +0100 Subject: [PATCH 071/114] Small fixes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 82a4e2a..c1a413a 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ cd /tmp && wget -q -O /tmp/install.sh https://raw.githubusercontent.com/sefinek/ ``` ### Manually -#### Node.js (Ubuntu & Debian) +#### Node.js installation (Ubuntu & Debian) ```bash sudo apt-get install -y curl curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh @@ -49,7 +49,7 @@ sudo -E bash nodesource_setup.sh sudo apt-get install -y nodejs ``` -#### Git +#### Git installation ```bash sudo add-apt-repository ppa:git-core/ppa sudo apt-get update && sudo apt-get -y install git From 5f62028f45774111414d234df7923edf0063cc45 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:04:16 +0100 Subject: [PATCH 072/114] Small fixes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c1a413a..60d12dc 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,12 @@ Also, check this out: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/s ## 📥 Installation ### Automatic (Easy & recommenced) -#### curl +#### Via curl ```bash cd /tmp && curl -s -o /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && sudo bash install.sh && rm install.sh ``` -#### wget +#### Via wget ```bash cd /tmp && wget -q -O /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && sudo bash install.sh && rm install.sh ``` From 5cb3dcde2ece611f4f711e1a87eaa5f5d9d09742 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:04:27 +0100 Subject: [PATCH 073/114] Small fixes --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 60d12dc..4888e66 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Also, check this out: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/s ## 📥 Installation -### Automatic (Easy & recommenced) +### Automatic (easy & recommenced) #### Via curl ```bash cd /tmp && curl -s -o /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && sudo bash install.sh && rm install.sh From 7c33b9585d876010a347176e047ff77b1ed55a95 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:05:00 +0100 Subject: [PATCH 074/114] Small fixes --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 4888e66..178ce23 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,7 @@ cd /tmp && wget -q -O /tmp/install.sh https://raw.githubusercontent.com/sefinek/ ```bash sudo apt-get install -y curl curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh -sudo -E bash nodesource_setup.sh -sudo apt-get install -y nodejs +sudo -E bash nodesource_setup.sh && sudo apt-get install -y nodejs ``` #### Git installation From 24c7a0ecd22cb250231c366162a558c6ba470946 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:06:32 +0100 Subject: [PATCH 075/114] Small fixes --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 178ce23..34c0326 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A utility designed to analyze UFW logs and report IP addresses blocked by the firewall to the [AbuseIPDB](https://www.abuseipdb.com) database. To prevent excessive reporting of the same IP address within a short period, the tool uses a temporary cache file to track previously reported IP addresses. -This project was previously written in Bash but has been rewritten in [Node.js](https://nodejs.org). All my integration tools are now written in Node, hence this change. +This project was originally written in Bash but has been rewritten in [Node.js](https://nodejs.org). All my integration tools are now written in Node, hence this change. If you were using the old version, please [uninstall it](https://github.com/sefinek/UFW-AbuseIPDB-Reporter/tree/node.js?tab=readme-ov-file#%EF%B8%8F-remove-the-old-version) as it will no longer be supported. If you like this repository or find it useful, I’d greatly appreciate it if you could give it a star ⭐. Many thanks! From 6fb234931297b85cb55a0426f679ba40c17f32c8 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:12:04 +0100 Subject: [PATCH 076/114] Small fixes --- install.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index 2917b53..0d7a20e 100644 --- a/install.sh +++ b/install.sh @@ -56,15 +56,24 @@ check_dependencies # Function to validate AbuseIPDB API key validate_token() { local api_key=$1 + local api_url="https://api.abuseipdb.com/api/v2/check?ipAddress=8.8.8.8" local response - response=$(curl -s -o /dev/null -w "%{http_code}" -H "Key: $api_key" https://api.abuseipdb.com/api/v2/check?ipAddress=8.8.8.8) + if command -v curl &>/dev/null; then + response=$(curl -s -o /dev/null -w "%{http_code}" -H "Key: $api_key" "$api_url") + elif command -v wget &>/dev/null; then + response=$(wget --quiet --server-response --header="Key: $api_key" --output-document=/dev/null "$api_url" 2>&1 | awk '/HTTP\/1\.[01] [0-9]{3}/ {print $2}' | tail -n1) + else + echo "❌ Neither curl nor wget is installed. Please install one of them to proceed." + exit 1 + fi if [[ $response -eq 200 ]]; then + echo "✅ Yay! Token is valid." return 0 else - echo "🚨 Invalid token. Please try again." - return 1 + echo "🚨 Invalid token or an error occurred! Please try again." + exit 1 fi } From f9503d988ec82fb6f4b865d677d8bb18c7d58d09 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:13:59 +0100 Subject: [PATCH 077/114] Small fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 0d7a20e..3cd2b18 100644 --- a/install.sh +++ b/install.sh @@ -73,7 +73,7 @@ validate_token() { return 0 else echo "🚨 Invalid token or an error occurred! Please try again." - exit 1 + validate_token fi } From 29d1fed3c63daff7fbfd20b00c523534b930386f Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:14:47 +0100 Subject: [PATCH 078/114] Small fixes --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 3cd2b18..b1b179a 100644 --- a/install.sh +++ b/install.sh @@ -64,7 +64,7 @@ validate_token() { elif command -v wget &>/dev/null; then response=$(wget --quiet --server-response --header="Key: $api_key" --output-document=/dev/null "$api_url" 2>&1 | awk '/HTTP\/1\.[01] [0-9]{3}/ {print $2}' | tail -n1) else - echo "❌ Neither curl nor wget is installed. Please install one of them to proceed." + echo "🚨 Neither curl nor wget is installed. Please install one of them to proceed." exit 1 fi @@ -72,7 +72,7 @@ validate_token() { echo "✅ Yay! Token is valid." return 0 else - echo "🚨 Invalid token or an error occurred! Please try again." + echo "❌ Invalid token! Please try again." validate_token fi } From 360ce7f18922237b188360628664c3cdd895fb70 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:17:12 +0100 Subject: [PATCH 079/114] Small fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index b1b179a..ae9b43f 100644 --- a/install.sh +++ b/install.sh @@ -73,7 +73,7 @@ validate_token() { return 0 else echo "❌ Invalid token! Please try again." - validate_token + return 1 fi } From 663eb37ef6a7d2c0c0432b621671d09f6b8f6302 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:17:28 +0100 Subject: [PATCH 080/114] Small fixes --- default.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.config.js b/default.config.js index 3baf9eb..bcca5eb 100644 --- a/default.config.js +++ b/default.config.js @@ -2,7 +2,7 @@ exports.MAIN = { // Server UFW_FILE: '/var/log/ufw.log', CACHE_FILE: '/tmp/ufw-abuseipdb-reporter.cache', - SERVER_ID: null, // The server name that will be visible in the reports (e.g. 'homeserver01'). If you don't want to define it, leave the value as null. + SERVER_ID: null, // The server name that will be visible in the reports (e.g., 'homeserver01'). If you don't want to define it, leave the value as null. // Reporting ABUSEIPDB_API_KEY: '', From 053f605c10d9e244e63bb69f227fae126424d42b Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:17:42 +0100 Subject: [PATCH 081/114] Small fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index ae9b43f..f385876 100644 --- a/install.sh +++ b/install.sh @@ -116,7 +116,7 @@ done # Prompt for system update and upgrade if yes_no_prompt "🛠️ Do you want the script to run apt update and apt upgrade for you?"; then echo "🔧 Updating and upgrading the system..." - apt-get update > /dev/null 2>&1 && apt-get upgrade + apt-get update && apt-get upgrade else echo "⏩ Skipping system update and upgrade..." fi From 41f43d3ff196a26b3ecf7ae3356c849773cc3f0a Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:17:53 +0100 Subject: [PATCH 082/114] Small fixes --- install.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/install.sh b/install.sh index f385876..cc0557b 100644 --- a/install.sh +++ b/install.sh @@ -117,8 +117,6 @@ done if yes_no_prompt "🛠️ Do you want the script to run apt update and apt upgrade for you?"; then echo "🔧 Updating and upgrading the system..." apt-get update && apt-get upgrade -else - echo "⏩ Skipping system update and upgrade..." fi # Clone repository From 92eef15f0a944ecd5b391e2141e2944eb23ce804 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:24:56 +0100 Subject: [PATCH 083/114] Small fixes --- install.sh | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/install.sh b/install.sh index cc0557b..093ea4c 100644 --- a/install.sh +++ b/install.sh @@ -120,15 +120,14 @@ if yes_no_prompt "🛠️ Do you want the script to run apt update and apt upgra fi # Clone repository -if [ -d "/home" ]; then - mkdir -p /home/new_directory - echo "📂 '/home/new_directory' has been created" +if [ ! -d "/opt" ]; then + mkdir -p /opt + echo "📂 '/opt' has been created" else - echo "❌ '/home' directory does not exist. Exiting..." - exit 1 + echo "✅ '/opt' directory already exists" fi -cd /home || { echo "❌ Failed to change directory to '/home'. Exiting..."; exit 1; } +cd /opt || { echo "❌ Failed to change directory to '/opt'. Exiting..."; exit 1; } if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then echo "📥 Cloning the UFW-AbuseIPDB-Reporter repository..." @@ -185,7 +184,7 @@ pm2 startup # Execute the command generated by pm2 startup echo "🔧 Complete pm2 startup configuration:" -sudo env PATH="$PATH":/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u "$USER" --hp /home/"$USER" +sudo env PATH="$PATH":/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u "$USER" --hp /opt/"$USER" pm2 save @@ -197,8 +196,8 @@ pm2 status echo -e "\n🎉 Installation and configuration completed!" echo -e "\n====================================== Summary ======================================" -echo "🔑 API Token : $api_token" echo "🖥️ Server ID : ${server_id:-null}" +echo "🔑 API Token : $api_token" echo "📂 Script : $PWD" echo "⚙️ Config File : $PWD/config.js" From c56891d05a90e4b29f8eb40c10c11db7a76ca01d Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:27:49 +0100 Subject: [PATCH 084/114] Small fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 093ea4c..6a3e73e 100644 --- a/install.sh +++ b/install.sh @@ -102,7 +102,7 @@ done # Prompt for server ID while true; do - read -r -p "🖥️ Enter the server ID. Leave blank if you do not wish to provide one (e.g., homeserver1): " server_id + read -r -p "🖥️ Enter the server ID (e.g., homeserver1). Leave blank if you do not wish to provide one: " server_id if [[ -z $server_id ]]; then server_id=null break From 6b9607065e4755b17c1cc6e453e6ce1f42530f0c Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:29:56 +0100 Subject: [PATCH 085/114] Small fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 6a3e73e..c8b6852 100644 --- a/install.sh +++ b/install.sh @@ -193,7 +193,7 @@ pm2 save echo -e "\n\n🌌 Checking PM2 status..." pm2 status -echo -e "\n🎉 Installation and configuration completed!" +echo -e "\n🎉 Installation and configuration completed! Use the 'pm2 logs' command to monitor logs in real time." echo -e "\n====================================== Summary ======================================" echo "🖥️ Server ID : ${server_id:-null}" From 6254d4742667d37f5725e81770fd521dd5ebcc07 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:36:15 +0100 Subject: [PATCH 086/114] Fixes --- install.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/install.sh b/install.sh index c8b6852..9d0725d 100644 --- a/install.sh +++ b/install.sh @@ -1,5 +1,7 @@ #!/usr/bin/env bash +USER=${SUDO_USER:-$(whoami)} + # Function to prompt for a Yes/no answer yes_no_prompt() { local prompt="$1" @@ -179,19 +181,19 @@ chown "$USER":"$USER" /var/log/ufw-abuseipdb -R # Configure pm2 echo "⚙️ Configuring PM2..." -pm2 start -pm2 startup +sudo -u "$USER" pm2 start +sudo -u "$USER" pm2 startup # Execute the command generated by pm2 startup -echo "🔧 Complete pm2 startup configuration:" +echo "🔧 Complete pm2 startup configuration (for $USER):" sudo env PATH="$PATH":/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u "$USER" --hp /opt/"$USER" -pm2 save +sudo -u "$USER" pm2 save # Final echo -e "\n\n🌌 Checking PM2 status..." -pm2 status +sudo -u "$USER" pm2 status echo -e "\n🎉 Installation and configuration completed! Use the 'pm2 logs' command to monitor logs in real time." From 51ec6f451ccbbd1b882ff4916c16925bc721c1d9 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:41:57 +0100 Subject: [PATCH 087/114] Fixes --- install.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/install.sh b/install.sh index 9d0725d..d36f576 100644 --- a/install.sh +++ b/install.sh @@ -1,7 +1,5 @@ #!/usr/bin/env bash -USER=${SUDO_USER:-$(whoami)} - # Function to prompt for a Yes/no answer yes_no_prompt() { local prompt="$1" @@ -121,7 +119,7 @@ if yes_no_prompt "🛠️ Do you want the script to run apt update and apt upgra apt-get update && apt-get upgrade fi -# Clone repository +# Clone repository & set permissions if [ ! -d "/opt" ]; then mkdir -p /opt echo "📂 '/opt' has been created" @@ -133,18 +131,20 @@ cd /opt || { echo "❌ Failed to change directory to '/opt'. Exiting..."; exit 1 if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then echo "📥 Cloning the UFW-AbuseIPDB-Reporter repository..." - git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js || { echo "❌ Failed to clone the repository. Exiting..."; exit 1; } + sudo git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js || { echo "❌ Failed to clone the repository. Exiting..."; exit 1; } else echo "✨ The UFW-AbuseIPDB-Reporter repository already exists!" fi +sudo chown "$USER":"$USER" /opt/UFW-AbuseIPDB-Reporter -R + echo "📥 Pulling latest changes..." cd UFW-AbuseIPDB-Reporter || { echo "❌ Failed to change directory to 'UFW-AbuseIPDB-Reporter'. Exiting..."; exit 1; } git pull || { echo "❌ Failed to pull the latest changes. Exiting..."; exit 1; } # Install npm dependencies echo "📦 Installing npm dependencies..." -npm install --silent +npm install # Copy configuration file echo "📑 Copying default.config.js to config.js..." @@ -168,32 +168,32 @@ chmod 644 "$ufw_log_path" # Uninstall corepack echo "🗑️ Uninstalling corepack..." -npm uninstall corepack -g --silent +sudo npm uninstall corepack -g # Install pm2 echo "📦 Installing PM2..." -npm install pm2 -g --silent +sudo npm install pm2 -g # Create logs directory echo "📂 Creating /var/log/ufw-abuseipdb directory..." -mkdir -p /var/log/ufw-abuseipdb -chown "$USER":"$USER" /var/log/ufw-abuseipdb -R +sudo mkdir -p /var/log/ufw-abuseipdb +sudo chown "$USER":"$USER" /var/log/ufw-abuseipdb -R # Configure pm2 echo "⚙️ Configuring PM2..." -sudo -u "$USER" pm2 start -sudo -u "$USER" pm2 startup +pm2 start +pm2 startup # Execute the command generated by pm2 startup echo "🔧 Complete pm2 startup configuration (for $USER):" sudo env PATH="$PATH":/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u "$USER" --hp /opt/"$USER" -sudo -u "$USER" pm2 save +pm2 save # Final echo -e "\n\n🌌 Checking PM2 status..." -sudo -u "$USER" pm2 status +pm2 status echo -e "\n🎉 Installation and configuration completed! Use the 'pm2 logs' command to monitor logs in real time." From 1c056de3b05aca55183429e99a44475aab665daf Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:50:55 +0100 Subject: [PATCH 088/114] Fixes --- install.sh | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/install.sh b/install.sh index d36f576..bcb1418 100644 --- a/install.sh +++ b/install.sh @@ -36,9 +36,9 @@ check_dependencies() { for dep in "${missing[@]}"; do if yes_no_prompt "📦 Do you want to install $dep?"; then case $dep in - curl ) apt-get install -y curl ;; - node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && bash nodesource_setup.sh && apt-get install -y nodejs && rm -f nodesource_setup.sh ;; - git ) add-apt-repository ppa:git-core/ppa && apt-get update && apt-get -y install git ;; + curl ) sudo apt-get install -y curl ;; + node ) curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh && sudo bash nodesource_setup.sh && sudo apt-get install -y nodejs && rm -f nodesource_setup.sh ;; + git ) sudo add-apt-repository ppa:git-core/ppa && sudo apt-get update && sudo apt-get -y install git ;; esac else echo "❌ Cannot proceed without $dep. Exiting..." @@ -81,7 +81,7 @@ validate_token() { if [[ ! -f /var/log/ufw.log ]]; then read -r -p "🔍 /var/log/ufw.log not found. Please enter the path to your log file: " ufw_log_path if [[ -f $ufw_log_path ]]; then - echo "✅ Log file found at $ufw_log_path." + echo "✅ Log file found at $ufw_log_path" else echo "❌ Provided log file path does not exist. Exiting..." exit 1 @@ -116,7 +116,7 @@ done # Prompt for system update and upgrade if yes_no_prompt "🛠️ Do you want the script to run apt update and apt upgrade for you?"; then echo "🔧 Updating and upgrading the system..." - apt-get update && apt-get upgrade + sudo apt-get update && sudo apt-get upgrade fi # Clone repository & set permissions @@ -164,7 +164,7 @@ fi # Change permissions for UFW log file echo "🔒 Changing permissions for $ufw_log_path..." -chmod 644 "$ufw_log_path" +sudo chmod 644 "$ufw_log_path" # Uninstall corepack echo "🗑️ Uninstalling corepack..." @@ -179,14 +179,17 @@ echo "📂 Creating /var/log/ufw-abuseipdb directory..." sudo mkdir -p /var/log/ufw-abuseipdb sudo chown "$USER":"$USER" /var/log/ufw-abuseipdb -R -# Configure pm2 +# Configure PM2 echo "⚙️ Configuring PM2..." -pm2 start -pm2 startup +startup_command=$(pm2 startup | grep "sudo env PATH" | sed 's/^[^s]*sudo/sudo/') -# Execute the command generated by pm2 startup -echo "🔧 Complete pm2 startup configuration (for $USER):" -sudo env PATH="$PATH":/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u "$USER" --hp /opt/"$USER" +if [ -n "$startup_command" ]; then + echo "🔧 Executing PM2 startup command..." + echo "📝 $startup_command" + eval "$startup_command" +else + echo "❌ Failed to find the command generated by 'pm2 startup'! PM2 was not added to autostart." +fi pm2 save From 6efe02c7ca697e32891a73d8033cbc214cd5cee8 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:52:05 +0100 Subject: [PATCH 089/114] Fixes --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index bcb1418..ba18c40 100644 --- a/install.sh +++ b/install.sh @@ -168,11 +168,11 @@ sudo chmod 644 "$ufw_log_path" # Uninstall corepack echo "🗑️ Uninstalling corepack..." -sudo npm uninstall corepack -g +sudo npm uninstall corepack -g -silent # Install pm2 echo "📦 Installing PM2..." -sudo npm install pm2 -g +sudo npm install pm2 -g -silent # Create logs directory echo "📂 Creating /var/log/ufw-abuseipdb directory..." From 2cc18a1cd13114f380a58a5e91a940430dc493b1 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:52:32 +0100 Subject: [PATCH 090/114] Fixes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 34c0326..c20e63c 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,12 @@ Also, check this out: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/s ### Automatic (easy & recommenced) #### Via curl ```bash -cd /tmp && curl -s -o /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && sudo bash install.sh && rm install.sh +cd /tmp && curl -s -o /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && bash install.sh && rm install.sh ``` #### Via wget ```bash -cd /tmp && wget -q -O /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && sudo bash install.sh && rm install.sh +cd /tmp && wget -q -O /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && bash install.sh && rm install.sh ``` ### Manually From f3d92a6349a6db00c10090669b9232d522492701 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 03:58:37 +0100 Subject: [PATCH 091/114] Fixes --- install.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/install.sh b/install.sh index ba18c40..1c4b8dc 100644 --- a/install.sh +++ b/install.sh @@ -162,6 +162,11 @@ else exit 1 fi +# Create logs directory +echo "📂 Creating /var/log/ufw-abuseipdb directory..." +sudo mkdir -p /var/log/ufw-abuseipdb +sudo chown "$USER":"$USER" /var/log/ufw-abuseipdb -R + # Change permissions for UFW log file echo "🔒 Changing permissions for $ufw_log_path..." sudo chmod 644 "$ufw_log_path" @@ -174,23 +179,18 @@ sudo npm uninstall corepack -g -silent echo "📦 Installing PM2..." sudo npm install pm2 -g -silent -# Create logs directory -echo "📂 Creating /var/log/ufw-abuseipdb directory..." -sudo mkdir -p /var/log/ufw-abuseipdb -sudo chown "$USER":"$USER" /var/log/ufw-abuseipdb -R - # Configure PM2 -echo "⚙️ Configuring PM2..." +echo "⚙️ Adding PM2 to autostart..." startup_command=$(pm2 startup | grep "sudo env PATH" | sed 's/^[^s]*sudo/sudo/') if [ -n "$startup_command" ]; then - echo "🔧 Executing PM2 startup command..." - echo "📝 $startup_command" + echo "⚙️ $startup_command..." eval "$startup_command" else echo "❌ Failed to find the command generated by 'pm2 startup'! PM2 was not added to autostart." fi +echo "⚙️ Running PM2 save..." pm2 save From c94690d2bbfdaaee4ab8a3c7ef35a51fcf2079da Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:04:40 +0100 Subject: [PATCH 092/114] Fixes --- install.sh | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/install.sh b/install.sh index 1c4b8dc..86dca1a 100644 --- a/install.sh +++ b/install.sh @@ -1,5 +1,36 @@ #!/usr/bin/env bash +################################################################## +# Copyright 2024-2025 (c) by Sefinek All rights reserved. +################################################################## + +DATE="18.01.2025" # DD.MM.YYYY + +cat << "EOF" + _ _ ___ ____ ____ ____ + / \ | |__ _ _ ___ ___ |_ _| | _ \ | _ \ | __ ) + / _ \ | '_ \ | | | | / __| / _ \ | | | |_) | | | | | | _ \ + / ___ \ | |_) | | |_| | \__ \ | __/ | | | __/ | |_| | | |_) | + /_/ \_\_|_.__/ _ \__,_| |___/ \___| |___| |_| |____/ |____/ + + (_)_ __ | |_ ___ __ _ _ __ __ _| |_(_) ___ _ __ + | | '_ \| __/ _ \/ _` | '__/ _` | __| |/ _ \| '_ \ + | | | | | || __/ (_| | | | (_| | |_| | (_) | | | | + |_|_| |_|\__\___|\__, |_| \__,_|\__|_|\___/|_| |_| + |___/ + +EOF + +cat <> Made by sefinek.net || Date: $DATE << + +This installer will configure UFW-AbuseIPDB-Reporter, a tool that analyzes UFW logs and +reports to AbuseIPDB the IP addresses that have violated firewall rules. Join my Discord +server to stay updated on the latest changes and more: https://discord.gg/53DBjTuzgZ +============================================================================================= + +EOF + # Function to prompt for a Yes/no answer yes_no_prompt() { local prompt="$1" From 583c1a0de5fac7bab91595a79a8b1045a33086b4 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:06:07 +0100 Subject: [PATCH 093/114] Fixes --- install.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/install.sh b/install.sh index 86dca1a..57b773c 100644 --- a/install.sh +++ b/install.sh @@ -7,27 +7,27 @@ DATE="18.01.2025" # DD.MM.YYYY cat << "EOF" - _ _ ___ ____ ____ ____ - / \ | |__ _ _ ___ ___ |_ _| | _ \ | _ \ | __ ) - / _ \ | '_ \ | | | | / __| / _ \ | | | |_) | | | | | | _ \ - / ___ \ | |_) | | |_| | \__ \ | __/ | | | __/ | |_| | | |_) | - /_/ \_\_|_.__/ _ \__,_| |___/ \___| |___| |_| |____/ |____/ + _ _ ___ ____ ____ ____ + / \ | |__ _ _ ___ ___ |_ _| | _ \ | _ \ | __ ) + / _ \ | '_ \ | | | | / __| / _ \ | | | |_) | | | | | | _ \ + / ___ \ | |_) | | |_| | \__ \ | __/ | | | __/ | |_| | | |_) | + /_/ \_\_|_.__/ _ \__,_| |___/ \___| |___| |_| |____/ |____/ - (_)_ __ | |_ ___ __ _ _ __ __ _| |_(_) ___ _ __ - | | '_ \| __/ _ \/ _` | '__/ _` | __| |/ _ \| '_ \ - | | | | | || __/ (_| | | | (_| | |_| | (_) | | | | - |_|_| |_|\__\___|\__, |_| \__,_|\__|_|\___/|_| |_| - |___/ + (_)_ __ | |_ ___ __ _ _ __ __ _| |_(_) ___ _ __ + | | '_ \| __/ _ \/ _` | '__/ _` | __| |/ _ \| '_ \ + | | | | | || __/ (_| | | | (_| | |_| | (_) | | | | + |_|_| |_|\__\___|\__, |_| \__,_|\__|_|\___/|_| |_| + |___/ EOF cat <> Made by sefinek.net || Date: $DATE << + >> Made by sefinek.net || Date: $DATE << This installer will configure UFW-AbuseIPDB-Reporter, a tool that analyzes UFW logs and reports to AbuseIPDB the IP addresses that have violated firewall rules. Join my Discord server to stay updated on the latest changes and more: https://discord.gg/53DBjTuzgZ -============================================================================================= +============================================================================================ EOF From 6378657cab01e3a1596bd3249a58fe210a463cb1 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:06:48 +0100 Subject: [PATCH 094/114] Fixes --- install.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/install.sh b/install.sh index 57b773c..caaac2b 100644 --- a/install.sh +++ b/install.sh @@ -4,8 +4,6 @@ # Copyright 2024-2025 (c) by Sefinek All rights reserved. ################################################################## -DATE="18.01.2025" # DD.MM.YYYY - cat << "EOF" _ _ ___ ____ ____ ____ / \ | |__ _ _ ___ ___ |_ _| | _ \ | _ \ | __ ) @@ -19,10 +17,7 @@ cat << "EOF" |_|_| |_|\__\___|\__, |_| \__,_|\__|_|\___/|_| |_| |___/ -EOF - -cat <> Made by sefinek.net || Date: $DATE << + >> Made by sefinek.net || Date: 18.01.2025 << This installer will configure UFW-AbuseIPDB-Reporter, a tool that analyzes UFW logs and reports to AbuseIPDB the IP addresses that have violated firewall rules. Join my Discord From 701e46285d65136080f24d696475c56b704b2762 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:14:27 +0100 Subject: [PATCH 095/114] Fixes --- install.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index caaac2b..c0327d1 100644 --- a/install.sh +++ b/install.sh @@ -170,11 +170,16 @@ git pull || { echo "❌ Failed to pull the latest changes. Exiting..."; exit 1; # Install npm dependencies echo "📦 Installing npm dependencies..." -npm install +npm install -silent # Copy configuration file -echo "📑 Copying default.config.js to config.js..." -cp default.config.js config.js +echo "📑 Checking if config.js exists..." +if [ -e config.js ]; then + echo "⚠️ config.js already exists. Skipping copy..." +else + echo "📑 Copying default.config.js to config.js..." + cp default.config.js config.js +fi # Update config.js with API token, Server ID, and UFW log path config_file="config.js" @@ -205,15 +210,18 @@ sudo npm uninstall corepack -g -silent echo "📦 Installing PM2..." sudo npm install pm2 -g -silent + # Configure PM2 echo "⚙️ Adding PM2 to autostart..." startup_command=$(pm2 startup | grep "sudo env PATH" | sed 's/^[^s]*sudo/sudo/') if [ -n "$startup_command" ]; then - echo "⚙️ $startup_command..." - eval "$startup_command" + echo "⚙️ Executing: $startup_command" + eval "$startup_command" &>/dev/null || { + echo "❌ Failed to execute the startup command!" + } else - echo "❌ Failed to find the command generated by 'pm2 startup'! PM2 was not added to autostart." + echo "❌ Failed to find the command generated by pm2 startup! PM2 was not added to autostart." fi echo "⚙️ Running PM2 save..." From 10422f4e6a0bbd312fd5a9bdbb2487955f2699d5 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:14:52 +0100 Subject: [PATCH 096/114] Fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index c0327d1..712e8c7 100644 --- a/install.sh +++ b/install.sh @@ -17,7 +17,7 @@ cat << "EOF" |_|_| |_|\__\___|\__, |_| \__,_|\__|_|\___/|_| |_| |___/ - >> Made by sefinek.net || Date: 18.01.2025 << + >> Made by sefinek.net || Last update: 18.01.2025 << This installer will configure UFW-AbuseIPDB-Reporter, a tool that analyzes UFW logs and reports to AbuseIPDB the IP addresses that have violated firewall rules. Join my Discord From 733414ee31dbbe9d70e515717bcade1173278853 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:15:06 +0100 Subject: [PATCH 097/114] Fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 712e8c7..e202808 100644 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash ################################################################## -# Copyright 2024-2025 (c) by Sefinek All rights reserved. +# Copyright 2024-2025 (c) by Sefinek All rights reserved. # ################################################################## cat << "EOF" From d68e37c10ccfee68648dc32b9cdd60bfc794d131 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:15:28 +0100 Subject: [PATCH 098/114] Fixes --- install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install.sh b/install.sh index e202808..05ffb04 100644 --- a/install.sh +++ b/install.sh @@ -2,6 +2,7 @@ ################################################################## # Copyright 2024-2025 (c) by Sefinek All rights reserved. # +# https://sefinek.net # ################################################################## cat << "EOF" From 4e78a24b6a29c27427567d5c6473994162c3a188 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:19:09 +0100 Subject: [PATCH 099/114] Fixes --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 05ffb04..de3cf44 100644 --- a/install.sh +++ b/install.sh @@ -226,7 +226,7 @@ else fi echo "⚙️ Running PM2 save..." -pm2 save +pm2 save --silent # Final From 4a51d910e40b5ab735f771814b71598a4c3a1f34 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:24:42 +0100 Subject: [PATCH 100/114] Fixes --- install.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index de3cf44..e351ecd 100644 --- a/install.sh +++ b/install.sh @@ -174,9 +174,8 @@ echo "📦 Installing npm dependencies..." npm install -silent # Copy configuration file -echo "📑 Checking if config.js exists..." if [ -e config.js ]; then - echo "⚠️ config.js already exists. Skipping copy..." + echo "✅ config.js already exists. Skipping copy..." else echo "📑 Copying default.config.js to config.js..." cp default.config.js config.js @@ -225,7 +224,8 @@ else echo "❌ Failed to find the command generated by pm2 startup! PM2 was not added to autostart." fi -echo "⚙️ Running PM2 save..." +echo "⚙️ Running a script with PM2 and saving the current state of all processes managed by it..." +pm2 start --silent pm2 save --silent From 782f0a77512ae58b15a9369271c4ae30d8122e7e Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:42:41 +0100 Subject: [PATCH 101/114] 0.1.1 --- index.js | 6 +++--- package-lock.json | 20 ++++++++++---------- package.json | 6 +++--- services/serverAddress.js | 40 +++++++++++++++++++++++++++++++++++++++ services/serverIp.js | 22 --------------------- 5 files changed, 56 insertions(+), 38 deletions(-) create mode 100644 services/serverAddress.js delete mode 100644 services/serverIp.js diff --git a/index.js b/index.js index 3372e0b..be75d98 100644 --- a/index.js +++ b/index.js @@ -6,7 +6,7 @@ const isLocalIP = require('./services/isLocalIP.js'); const { reportedIPs, loadReportedIPs, saveReportedIPs, isIPReportedRecently, markIPAsReported } = require('./services/cache.js'); const log = require('./utils/log.js'); const axios = require('./services/axios.js'); -const getServerIP = require('./services/serverIp.js'); +const serverAddress = require('./services/serverAddress.js'); const config = require('./config.js'); const { version } = require('./package.json'); const { UFW_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; @@ -63,8 +63,8 @@ const processLogLine = async line => { return; } - if (srcIp === getServerIP()) { - log(0, 'Ignoring own IP'); + if (serverAddress().includes(srcIp)) { + log(0, `Ignoring own IP address: ${srcIp}`); return; } diff --git a/package-lock.json b/package-lock.json index a73791d..a0b417d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ufw-abuseipdb-reporter", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ufw-abuseipdb-reporter", - "version": "0.1.0", + "version": "0.1.1", "license": "GPL-3.0", "dependencies": { "axios": "^1.7.9", @@ -14,14 +14,14 @@ "ipaddr.js": "^2.2.0" }, "devDependencies": { - "@eslint/js": "^9.17.0", + "@eslint/js": "^9.18.0", "globals": "^15.14.0" } }, "node_modules/@eslint/js": { - "version": "9.17.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", - "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", + "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", "dev": true, "license": "MIT", "engines": { @@ -165,12 +165,12 @@ "license": "MIT" }, "node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.1.tgz", + "integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==", "license": "MIT", "engines": { - "node": ">= 14.16.0" + "node": ">= 14.18.0" }, "funding": { "type": "individual", diff --git a/package.json b/package.json index e34f6e5..00fda1b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ufw-abuseipdb-reporter", - "version": "0.1.0", - "description": "", + "version": "0.1.1", + "description": "A tool (with a simple installer) that monitors UFW firewall logs in real time and reports IP addresses to the AbuseIPDB database.", "keywords": [ "ufw", "abuseipdb" @@ -28,7 +28,7 @@ "ipaddr.js": "^2.2.0" }, "devDependencies": { - "@eslint/js": "^9.17.0", + "@eslint/js": "^9.18.0", "globals": "^15.14.0" } } diff --git a/services/serverAddress.js b/services/serverAddress.js new file mode 100644 index 0000000..8e5a53d --- /dev/null +++ b/services/serverAddress.js @@ -0,0 +1,40 @@ +const os = require('node:os'); +const axios = require('./axios.js'); +const isLocalIP = require('./isLocalIP.js'); + +let ipAddressList = []; + +const fetchIPv4Address = async () => { + try { + const { data } = await axios.get('https://api.sefinek.net/api/v2/ip'); + if (data?.success && data?.message) ipAddressList.push(data.message); + } catch (err) { + console.warn('Error fetching IPv4 address:', err.message); + } +}; + +const fetchIPv6Address = () => { + const networkInterfaces = os.networkInterfaces(); + + for (const interfaces of Object.values(networkInterfaces)) { + for (const details of interfaces) { + const ip = details.address; + if (!details.internal && ip && !isLocalIP(ip)) ipAddressList.push(ip); + } + } +}; + +const fetchIPAddress = async () => { + ipAddressList = []; + await fetchIPv4Address(); + fetchIPv6Address(); +}; + +(async () => { + await fetchIPAddress(); + setInterval(fetchIPAddress, 25 * 1000); + + console.log(ipAddressList); +})(); + +module.exports = () => [...ipAddressList]; \ No newline at end of file diff --git a/services/serverIp.js b/services/serverIp.js deleted file mode 100644 index 6a08bf0..0000000 --- a/services/serverIp.js +++ /dev/null @@ -1,22 +0,0 @@ -const axios = require('./axios.js'); - -let address = null; - -const fetchIPAddress = async () => { - if (address) return; - - try { - const { data } = await axios.get('https://api.sefinek.net/api/v2/ip'); - if (data?.success && data?.message) { - address = data.message; - } else { - setTimeout(fetchIPAddress, 20 * 1000); - } - } catch { - setTimeout(fetchIPAddress, 25 * 1000); - } -}; - -(async () => fetchIPAddress())(); - -module.exports = () => address; \ No newline at end of file From ef7ccca12e46145cebaeb25dd75b658431504abe Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:44:56 +0100 Subject: [PATCH 102/114] Some update --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index e351ecd..6b460fc 100644 --- a/install.sh +++ b/install.sh @@ -230,7 +230,7 @@ pm2 save --silent # Final -echo -e "\n\n🌌 Checking PM2 status..." +echo "🌌 Checking PM2 status..." pm2 status echo -e "\n🎉 Installation and configuration completed! Use the 'pm2 logs' command to monitor logs in real time." From 590fd37831f8da78dbbea175b2465cf938ba7637 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:45:44 +0100 Subject: [PATCH 103/114] Cleanup --- services/serverAddress.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/serverAddress.js b/services/serverAddress.js index 8e5a53d..c6c48fc 100644 --- a/services/serverAddress.js +++ b/services/serverAddress.js @@ -33,8 +33,6 @@ const fetchIPAddress = async () => { (async () => { await fetchIPAddress(); setInterval(fetchIPAddress, 25 * 1000); - - console.log(ipAddressList); })(); module.exports = () => [...ipAddressList]; \ No newline at end of file From f6774898b5d51df10b0583137c0adfa270316451 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:48:11 +0100 Subject: [PATCH 104/114] Quality fixes --- services/serverAddress.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/services/serverAddress.js b/services/serverAddress.js index c6c48fc..80b8723 100644 --- a/services/serverAddress.js +++ b/services/serverAddress.js @@ -2,12 +2,12 @@ const os = require('node:os'); const axios = require('./axios.js'); const isLocalIP = require('./isLocalIP.js'); -let ipAddressList = []; +const ipAddressList = new Set(); const fetchIPv4Address = async () => { try { const { data } = await axios.get('https://api.sefinek.net/api/v2/ip'); - if (data?.success && data?.message) ipAddressList.push(data.message); + if (data?.success && data?.message) ipAddressList.add(data.message); } catch (err) { console.warn('Error fetching IPv4 address:', err.message); } @@ -16,16 +16,18 @@ const fetchIPv4Address = async () => { const fetchIPv6Address = () => { const networkInterfaces = os.networkInterfaces(); - for (const interfaces of Object.values(networkInterfaces)) { - for (const details of interfaces) { + Object.values(networkInterfaces).forEach(interfaces => { + interfaces.forEach(details => { const ip = details.address; - if (!details.internal && ip && !isLocalIP(ip)) ipAddressList.push(ip); - } - } + if (!details.internal && ip && !isLocalIP(ip)) { + ipAddressList.add(ip); + } + }); + }); }; const fetchIPAddress = async () => { - ipAddressList = []; + ipAddressList.clear(); await fetchIPv4Address(); fetchIPv6Address(); }; @@ -33,6 +35,8 @@ const fetchIPAddress = async () => { (async () => { await fetchIPAddress(); setInterval(fetchIPAddress, 25 * 1000); + + // console.debug(ipAddressList); })(); -module.exports = () => [...ipAddressList]; \ No newline at end of file +module.exports = () => Array.from(ipAddressList); \ No newline at end of file From 1239a9f1b3871b02edf7d2f101d882a8e6421ddb Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:49:44 +0100 Subject: [PATCH 105/114] Some fixes --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 6b460fc..04e1043 100644 --- a/install.sh +++ b/install.sh @@ -160,7 +160,7 @@ if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then echo "📥 Cloning the UFW-AbuseIPDB-Reporter repository..." sudo git clone https://github.com/sefinek/UFW-AbuseIPDB-Reporter.git --branch node.js || { echo "❌ Failed to clone the repository. Exiting..."; exit 1; } else - echo "✨ The UFW-AbuseIPDB-Reporter repository already exists!" + echo "✨ The UFW-AbuseIPDB-Reporter repository already exists" fi sudo chown "$USER":"$USER" /opt/UFW-AbuseIPDB-Reporter -R @@ -175,7 +175,7 @@ npm install -silent # Copy configuration file if [ -e config.js ]; then - echo "✅ config.js already exists. Skipping copy..." + echo "✅ config.js already exists" else echo "📑 Copying default.config.js to config.js..." cp default.config.js config.js From 39ce55389237e64dd29a28ab4a5266650ebb6ba6 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 04:59:51 +0100 Subject: [PATCH 106/114] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c20e63c..17e79dd 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,12 @@ Also, check this out: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/s ### Automatic (easy & recommenced) #### Via curl ```bash -cd /tmp && curl -s -o /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && bash install.sh && rm install.sh +bash <(curl -fsS https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh) ``` #### Via wget ```bash -cd /tmp && wget -q -O /tmp/install.sh https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh && bash install.sh && rm install.sh +bash <(wget -qO- https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh) ``` ### Manually From 699354b85a3fa34be4916f628e862ca27e9e220a Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 15:29:40 +0100 Subject: [PATCH 107/114] Fixes --- default.config.js | 9 +++++---- index.js | 26 ++++++++++++++------------ install.sh | 2 +- services/cache.js | 4 ++-- services/serverAddress.js | 5 +++-- {services => utils}/isLocalIP.js | 0 6 files changed, 25 insertions(+), 21 deletions(-) rename {services => utils}/isLocalIP.js (100%) diff --git a/default.config.js b/default.config.js index bcca5eb..05e483b 100644 --- a/default.config.js +++ b/default.config.js @@ -1,12 +1,13 @@ exports.MAIN = { - // Server - UFW_FILE: '/var/log/ufw.log', + // This server + UFW_LOG_FILE: '/var/log/ufw.log', CACHE_FILE: '/tmp/ufw-abuseipdb-reporter.cache', SERVER_ID: null, // The server name that will be visible in the reports (e.g., 'homeserver01'). If you don't want to define it, leave the value as null. + REFRESHING_IP_ADDRESS: 5 * 60 * 1000, // How often should (every 5 minutes) the script check the server's IP address to avoid accidental self-reports? // Reporting - ABUSEIPDB_API_KEY: '', - REPORT_INTERVAL: 12 * 60 * 60 * 1000, // 12h + ABUSEIPDB_API_KEY: '', // Secret API key for AbuseIPDB. + IP_REPORT_COOLDOWN: 12 * 60 * 60 * 1000, // The minimum time (12 hours) that must pass before reporting the same IP address again. // Project GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', // If you are using a fork, provide the link to the forked repository here. diff --git a/index.js b/index.js index be75d98..efe2cb3 100644 --- a/index.js +++ b/index.js @@ -1,27 +1,30 @@ -// Copyright 2024 © by Sefinek. All rights reserved. +// +// Copyright 2024-2025 (c) by Sefinek All rights reserved. +// https://sefinek.net +// const fs = require('node:fs'); const chokidar = require('chokidar'); -const isLocalIP = require('./services/isLocalIP.js'); +const isLocalIP = require('./utils/isLocalIP.js'); const { reportedIPs, loadReportedIPs, saveReportedIPs, isIPReportedRecently, markIPAsReported } = require('./services/cache.js'); const log = require('./utils/log.js'); const axios = require('./services/axios.js'); const serverAddress = require('./services/serverAddress.js'); const config = require('./config.js'); const { version } = require('./package.json'); -const { UFW_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; +const { UFW_LOG_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; let fileOffset = 0; const reportToAbuseIPDb = async (logData, categories, comment) => { try { - const { data } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ + const { data: res } = await axios.post('https://api.abuseipdb.com/api/v2/report', new URLSearchParams({ ip: logData.srcIp, categories, comment, }), { headers: { 'Key': ABUSEIPDB_API_KEY } }); - log(0, `Reported ${logData.srcIp} [${logData.dpt}/${logData.proto}]; ID: ${logData.id}; Categories ${categories}; Abuse: ${data.data.abuseConfidenceScore}%`); + log(0, `Reported ${logData.srcIp} [${logData.dpt}/${logData.proto}]; ID: ${logData.id}; Categories ${categories}; Abuse: ${res.data.abuseConfidenceScore}%`); return true; } catch (err) { log(2, `Failed to report ${logData.srcIp} [${logData.dpt}/${logData.proto}]; ID: ${logData.id}; ${err.message}\n${JSON.stringify(err.response.data?.errors || err.response.data)}`); @@ -111,19 +114,18 @@ const processLogLine = async line => { }; (async () => { - log(0, `* Version: ${version}`); - log(0, `* Repository: ${GITHUB_REPO}`); + log(0, `v${version} (${GITHUB_REPO})`); loadReportedIPs(); - if (!fs.existsSync(UFW_FILE)) { - log(2, `Log file ${UFW_FILE} does not exist.`); + if (!fs.existsSync(UFW_LOG_FILE)) { + log(2, `Log file ${UFW_LOG_FILE} does not exist.`); return; } - fileOffset = fs.statSync(UFW_FILE).size; + fileOffset = fs.statSync(UFW_LOG_FILE).size; - chokidar.watch(UFW_FILE, { persistent: true, ignoreInitial: true }) + chokidar.watch(UFW_LOG_FILE, { persistent: true, ignoreInitial: true }) .on('change', path => { const stats = fs.statSync(path); if (stats.size < fileOffset) { @@ -140,6 +142,6 @@ const processLogLine = async line => { if (process?.send) process.send('ready'); - log(0, `Ready! Now monitoring: ${UFW_FILE}`); + log(0, `Ready! Now monitoring: ${UFW_LOG_FILE}`); log(0, '====================================================================='); })(); \ No newline at end of file diff --git a/install.sh b/install.sh index 04e1043..bcbb9de 100644 --- a/install.sh +++ b/install.sh @@ -185,7 +185,7 @@ fi config_file="config.js" if [[ -f $config_file ]]; then echo "🔧 Updating $PWD/$config_file..." - sed -i "s|UFW_FILE: .*|UFW_FILE: '$ufw_log_path',|" $config_file + sed -i "s|UFW_LOG_FILE: .*|UFW_LOG_FILE: '$ufw_log_path',|" $config_file sed -i "s|SERVER_ID: .*|SERVER_ID: '$server_id',|" $config_file sed -i "s|ABUSEIPDB_API_KEY: .*|ABUSEIPDB_API_KEY: '$api_token',|" $config_file else diff --git a/services/cache.js b/services/cache.js index 77871e8..0911d27 100644 --- a/services/cache.js +++ b/services/cache.js @@ -1,5 +1,5 @@ const fs = require('node:fs'); -const { CACHE_FILE, REPORT_INTERVAL } = require('../config.js').MAIN; +const { CACHE_FILE, IP_REPORT_COOLDOWN } = require('../config.js').MAIN; const log = require('../utils/log.js'); const reportedIPs = new Map(); @@ -22,7 +22,7 @@ const saveReportedIPs = () => fs.writeFileSync(CACHE_FILE, Array.from(reportedIP const isIPReportedRecently = ip => { const reportedTime = reportedIPs.get(ip); - return reportedTime && (Date.now() / 1000 - reportedTime < REPORT_INTERVAL / 1000); + return reportedTime && (Date.now() / 1000 - reportedTime < IP_REPORT_COOLDOWN / 1000); }; const markIPAsReported = ip => reportedIPs.set(ip, Math.floor(Date.now() / 1000)); diff --git a/services/serverAddress.js b/services/serverAddress.js index 80b8723..2b462ce 100644 --- a/services/serverAddress.js +++ b/services/serverAddress.js @@ -1,6 +1,7 @@ const os = require('node:os'); const axios = require('./axios.js'); -const isLocalIP = require('./isLocalIP.js'); +const isLocalIP = require('../utils/isLocalIP.js'); +const { MAIN } = require('../config.js'); const ipAddressList = new Set(); @@ -34,7 +35,7 @@ const fetchIPAddress = async () => { (async () => { await fetchIPAddress(); - setInterval(fetchIPAddress, 25 * 1000); + setInterval(fetchIPAddress, MAIN.REFRESHING_IP_ADDRESS); // console.debug(ipAddressList); })(); diff --git a/services/isLocalIP.js b/utils/isLocalIP.js similarity index 100% rename from services/isLocalIP.js rename to utils/isLocalIP.js From 83224274571dba138c1f12645ab18e6488ddcb48 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 18 Jan 2025 15:51:08 +0100 Subject: [PATCH 108/114] Update --- README.md | 4 +- default.config.js | 4 ++ index.js | 3 ++ package-lock.json | 82 ++++++++++++++++++++++++++++++++++++++- package.json | 4 +- services/reloadApp.js | 19 +++++++++ services/serverAddress.js | 8 ++-- update.js | 28 +++++++++++++ 8 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 services/reloadApp.js create mode 100644 update.js diff --git a/README.md b/README.md index 17e79dd..8f748b7 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,12 @@ Also, check this out: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/s ## ✅ Features -1. A `config.js` file enabling easy configuration. +1. A [`config.js`](default.config.js) file enabling easy configuration. 2. A simple installer allowing quick integration deployment. 3. Integration with Discord Webhooks (coming soon): - Alerts in case of script errors - Daily summaries of reported IP addresses - +4. Automatic updates. ## 📥 Installation diff --git a/default.config.js b/default.config.js index 05e483b..7f8e433 100644 --- a/default.config.js +++ b/default.config.js @@ -9,6 +9,10 @@ exports.MAIN = { ABUSEIPDB_API_KEY: '', // Secret API key for AbuseIPDB. IP_REPORT_COOLDOWN: 12 * 60 * 60 * 1000, // The minimum time (12 hours) that must pass before reporting the same IP address again. + // Automatic updates + AUTO_UPDATE_SCHEDULE: '0 18 * * *', // Schedule for automatic script updates (CRON format). Default: every day at 18:00 + AUTO_UPDATE_ENABLED: true, // Do you want the script to automatically update to the latest version using 'git pull'? (true = enabled, false = disabled) + // Project GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', // If you are using a fork, provide the link to the forked repository here. }; diff --git a/index.js b/index.js index efe2cb3..1e001ab 100644 --- a/index.js +++ b/index.js @@ -14,6 +14,9 @@ const config = require('./config.js'); const { version } = require('./package.json'); const { UFW_LOG_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; +// Updates +require('./update.js'); + let fileOffset = 0; const reportToAbuseIPDb = async (logData, categories, comment) => { diff --git a/package-lock.json b/package-lock.json index a0b417d..e87a728 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,9 @@ "dependencies": { "axios": "^1.7.9", "chokidar": "^4.0.3", - "ipaddr.js": "^2.2.0" + "cron": "^3.5.0", + "ipaddr.js": "^2.2.0", + "simple-git": "^3.27.0" }, "devDependencies": { "@eslint/js": "^9.18.0", @@ -28,6 +30,27 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "license": "MIT" + }, + "node_modules/@types/luxon": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz", + "integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==", + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -72,6 +95,33 @@ "node": ">= 0.8" } }, + "node_modules/cron": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/cron/-/cron-3.5.0.tgz", + "integrity": "sha512-0eYZqCnapmxYcV06uktql93wNWdlTmmBFP2iYz+JPVcQqlyFYcn1lFuIk4R54pkOmE7mcldTAPZv6X5XA4Q46A==", + "license": "MIT", + "dependencies": { + "@types/luxon": "~3.4.0", + "luxon": "~3.5.0" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -137,6 +187,15 @@ "node": ">= 10" } }, + "node_modules/luxon": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", + "integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -158,6 +217,12 @@ "node": ">= 0.6" } }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -176,6 +241,21 @@ "type": "individual", "url": "https://paulmillr.com/funding/" } + }, + "node_modules/simple-git": { + "version": "3.27.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz", + "integrity": "sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==", + "license": "MIT", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } } } } diff --git a/package.json b/package.json index 00fda1b..bde4ad2 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,9 @@ "dependencies": { "axios": "^1.7.9", "chokidar": "^4.0.3", - "ipaddr.js": "^2.2.0" + "cron": "^3.5.0", + "ipaddr.js": "^2.2.0", + "simple-git": "^3.27.0" }, "devDependencies": { "@eslint/js": "^9.18.0", diff --git a/services/reloadApp.js b/services/reloadApp.js new file mode 100644 index 0000000..67f5167 --- /dev/null +++ b/services/reloadApp.js @@ -0,0 +1,19 @@ +const { exec } = require('node:child_process'); +const ecosystem = require('../ecosystem.config.js'); + +const executeCommand = cmd => + new Promise((resolve, reject) => { + exec(cmd, (err, stdout, stderr) => { + if (err || stderr) reject(err || stderr); + else resolve(stdout); + }); + }); + +module.exports = async () => { + try { + console.log(await executeCommand('npm install --omit=dev')); + console.log(await executeCommand(`pm2 restart ${ecosystem.apps[0].name}`)); + } catch (err) { + console.error(err); + } +}; \ No newline at end of file diff --git a/services/serverAddress.js b/services/serverAddress.js index 2b462ce..cae1c01 100644 --- a/services/serverAddress.js +++ b/services/serverAddress.js @@ -1,7 +1,7 @@ const os = require('node:os'); const axios = require('./axios.js'); const isLocalIP = require('../utils/isLocalIP.js'); -const { MAIN } = require('../config.js'); +const { REFRESHING_IP_ADDRESS } = require('../config.js').MAIN; const ipAddressList = new Set(); @@ -20,9 +20,7 @@ const fetchIPv6Address = () => { Object.values(networkInterfaces).forEach(interfaces => { interfaces.forEach(details => { const ip = details.address; - if (!details.internal && ip && !isLocalIP(ip)) { - ipAddressList.add(ip); - } + if (!details.internal && ip && !isLocalIP(ip)) ipAddressList.add(ip); }); }); }; @@ -35,7 +33,7 @@ const fetchIPAddress = async () => { (async () => { await fetchIPAddress(); - setInterval(fetchIPAddress, MAIN.REFRESHING_IP_ADDRESS); + setInterval(fetchIPAddress, REFRESHING_IP_ADDRESS); // console.debug(ipAddressList); })(); diff --git a/update.js b/update.js new file mode 100644 index 0000000..997f9c1 --- /dev/null +++ b/update.js @@ -0,0 +1,28 @@ +const { SERVER_ID, AUTO_UPDATE_SCHEDULE, AUTO_UPDATE_ENABLED } = require('./config.js').MAIN; + +if (AUTO_UPDATE_ENABLED) { + const simpleGit = require('simple-git'); + const { CronJob } = require('cron'); + const restartApp = require('./services/reloadApp.js'); + const log = require('./utils/log.js'); + + const git = simpleGit(); + + const updateScript = async () => { + log(0, 'The script is being updated...'); + + try { + const { summary } = await git.pull(); + log(0, `Changes: ${summary.changes}; Deletions: ${summary.insertions}; Insertions: ${summary.insertions};`); + + if (SERVER_ID !== 'development') await restartApp(); + } catch (err) { + log(2, err.message); + } + }; + + // https://crontab.guru + new CronJob(AUTO_UPDATE_SCHEDULE || '0 18 * * *', updateScript, null, true, 'UTC'); // At 18:00 + + if (SERVER_ID === 'development') (async () => updateScript())(); +} \ No newline at end of file From cc6e256ca475d9cf1af79c24f413b654c7110686 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 1 Feb 2025 20:10:33 +0100 Subject: [PATCH 109/114] =?UTF-8?q?@eslint/js=20=20^9.18.0=20=20=E2=86=92?= =?UTF-8?q?=20=20^9.19.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e87a728..3d8c270 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,14 +16,14 @@ "simple-git": "^3.27.0" }, "devDependencies": { - "@eslint/js": "^9.18.0", + "@eslint/js": "^9.19.0", "globals": "^15.14.0" } }, "node_modules/@eslint/js": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz", - "integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==", + "version": "9.19.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz", + "integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index bde4ad2..6136a2b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "simple-git": "^3.27.0" }, "devDependencies": { - "@eslint/js": "^9.18.0", + "@eslint/js": "^9.19.0", "globals": "^15.14.0" } } From d5921f19e762bbdc4dfd753335e617ca0c877b41 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 1 Feb 2025 20:14:45 +0100 Subject: [PATCH 110/114] Update `fetchServerIP` --- index.js | 2 +- services/fetchServerIP.js | 40 ++++++++++++++++++++++++++++++++++++++ services/serverAddress.js | 41 --------------------------------------- 3 files changed, 41 insertions(+), 42 deletions(-) create mode 100644 services/fetchServerIP.js delete mode 100644 services/serverAddress.js diff --git a/index.js b/index.js index 1e001ab..7600ef4 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ const isLocalIP = require('./utils/isLocalIP.js'); const { reportedIPs, loadReportedIPs, saveReportedIPs, isIPReportedRecently, markIPAsReported } = require('./services/cache.js'); const log = require('./utils/log.js'); const axios = require('./services/axios.js'); -const serverAddress = require('./services/serverAddress.js'); +const serverAddress = require('./services/fetchServerIP.js'); const config = require('./config.js'); const { version } = require('./package.json'); const { UFW_LOG_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; diff --git a/services/fetchServerIP.js b/services/fetchServerIP.js new file mode 100644 index 0000000..af23c45 --- /dev/null +++ b/services/fetchServerIP.js @@ -0,0 +1,40 @@ +const { networkInterfaces } = require('node:os'); +const axios = require('./axios.js'); +const isLocalIP = require('../utils/isLocalIP.js'); +const { REFRESHING_IP_ADDRESS } = require('../config.js').MAIN; + +const ipAddrList = new Set(); + +const fetchIPv4Address = async () => { + try { + const { data } = await axios.get('https://api.sefinek.net/api/v2/ip'); + if (data?.success && data?.message) ipAddrList.add(data.message); + } catch (err) { + console.warn('Error fetching IPv4 address:', err.message); + } +}; + +const fetchIPv6Address = () => { + try { + Object.values(networkInterfaces()).flat().forEach(({ address, internal }) => { + if (!internal && address && !isLocalIP(address)) ipAddrList.add(address); + }); + } catch (err) { + console.warn('Error fetching IPv6 address:', err.message); + } +}; + +const fetchServerIPs = async () => { + ipAddrList.clear(); + await fetchIPv4Address(); + fetchIPv6Address(); +}; + +(async () => { + await fetchServerIPs(); + setInterval(fetchServerIPs, REFRESHING_IP_ADDRESS); + + // console.debug(ipAddrList); +})(); + +module.exports = () => Array.from(ipAddrList); \ No newline at end of file diff --git a/services/serverAddress.js b/services/serverAddress.js deleted file mode 100644 index cae1c01..0000000 --- a/services/serverAddress.js +++ /dev/null @@ -1,41 +0,0 @@ -const os = require('node:os'); -const axios = require('./axios.js'); -const isLocalIP = require('../utils/isLocalIP.js'); -const { REFRESHING_IP_ADDRESS } = require('../config.js').MAIN; - -const ipAddressList = new Set(); - -const fetchIPv4Address = async () => { - try { - const { data } = await axios.get('https://api.sefinek.net/api/v2/ip'); - if (data?.success && data?.message) ipAddressList.add(data.message); - } catch (err) { - console.warn('Error fetching IPv4 address:', err.message); - } -}; - -const fetchIPv6Address = () => { - const networkInterfaces = os.networkInterfaces(); - - Object.values(networkInterfaces).forEach(interfaces => { - interfaces.forEach(details => { - const ip = details.address; - if (!details.internal && ip && !isLocalIP(ip)) ipAddressList.add(ip); - }); - }); -}; - -const fetchIPAddress = async () => { - ipAddressList.clear(); - await fetchIPv4Address(); - fetchIPv6Address(); -}; - -(async () => { - await fetchIPAddress(); - setInterval(fetchIPAddress, REFRESHING_IP_ADDRESS); - - // console.debug(ipAddressList); -})(); - -module.exports = () => Array.from(ipAddressList); \ No newline at end of file From 5320952ccbf8cc3e5fe9da71eec24836134811b8 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 1 Feb 2025 20:29:35 +0100 Subject: [PATCH 111/114] 0.1.2 --- default.config.js | 3 --- index.js | 19 ++++++++++--------- package-lock.json | 4 ++-- package.json | 2 +- services/axios.js | 3 +-- services/cache.js | 8 ++++---- services/updates.js | 29 +++++++++++++++++++++++++++++ update.js | 28 ---------------------------- 8 files changed, 47 insertions(+), 49 deletions(-) create mode 100644 services/updates.js delete mode 100644 update.js diff --git a/default.config.js b/default.config.js index 7f8e433..cb42edb 100644 --- a/default.config.js +++ b/default.config.js @@ -12,9 +12,6 @@ exports.MAIN = { // Automatic updates AUTO_UPDATE_SCHEDULE: '0 18 * * *', // Schedule for automatic script updates (CRON format). Default: every day at 18:00 AUTO_UPDATE_ENABLED: true, // Do you want the script to automatically update to the latest version using 'git pull'? (true = enabled, false = disabled) - - // Project - GITHUB_REPO: 'https://github.com/sefinek/UFW-AbuseIPDB-Reporter', // If you are using a fork, provide the link to the forked repository here. }; diff --git a/index.js b/index.js index 7600ef4..1be416c 100644 --- a/index.js +++ b/index.js @@ -12,10 +12,7 @@ const axios = require('./services/axios.js'); const serverAddress = require('./services/fetchServerIP.js'); const config = require('./config.js'); const { version } = require('./package.json'); -const { UFW_LOG_FILE, ABUSEIPDB_API_KEY, SERVER_ID, GITHUB_REPO } = config.MAIN; - -// Updates -require('./update.js'); +const { UFW_LOG_FILE, ABUSEIPDB_API_KEY, SERVER_ID, AUTO_UPDATE_ENABLED } = config.MAIN; let fileOffset = 0; @@ -38,12 +35,10 @@ const reportToAbuseIPDb = async (logData, categories, comment) => { const processLogLine = async line => { if (!line.includes('[UFW BLOCK]')) return log(1, `Ignoring line: ${line}`); - const oldTime = line.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?/)?.[0]; const timestampMatch = line.match(/\[(\d+\.\d+)\]/); - const newTime = timestampMatch ? parseFloat(timestampMatch[1]) : null; const logData = { - timestampOld: oldTime || null, - timestampNew: newTime || null, + timestampOld: line.match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[+-]\d{2}:\d{2})?/)?.[0] || null, + timestampNew: (timestampMatch ? parseFloat(timestampMatch[1]) : null) || null, In: line.match(/IN=([\d.]+)/)?.[1] || null, Out: line.match(/OUT=([\d.]+)/)?.[1] || null, srcIp: line.match(/SRC=([\d.]+)/)?.[1] || null, @@ -117,7 +112,7 @@ const processLogLine = async line => { }; (async () => { - log(0, `v${version} (${GITHUB_REPO})`); + log(0, `v${version} (https://github.com/sefinek/UFW-AbuseIPDB-Reporter)`); loadReportedIPs(); @@ -147,4 +142,10 @@ const processLogLine = async line => { log(0, `Ready! Now monitoring: ${UFW_LOG_FILE}`); log(0, '====================================================================='); + + // Auto updates + if (AUTO_UPDATE_ENABLED) { + const autoUpdates = require('./services/updates.js'); + await autoUpdates.pull(); + } })(); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3d8c270..959f999 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ufw-abuseipdb-reporter", - "version": "0.1.1", + "version": "0.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ufw-abuseipdb-reporter", - "version": "0.1.1", + "version": "0.1.2", "license": "GPL-3.0", "dependencies": { "axios": "^1.7.9", diff --git a/package.json b/package.json index 6136a2b..e028517 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ufw-abuseipdb-reporter", - "version": "0.1.1", + "version": "0.1.2", "description": "A tool (with a simple installer) that monitors UFW firewall logs in real time and reports IP addresses to the AbuseIPDB database.", "keywords": [ "ufw", diff --git a/services/axios.js b/services/axios.js index 3feccab..c329bae 100644 --- a/services/axios.js +++ b/services/axios.js @@ -1,9 +1,8 @@ const axios = require('axios'); const { version } = require('../package.json'); -const { GITHUB_REPO } = require('../config.js').MAIN; axios.defaults.headers.common = { - 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +${GITHUB_REPO})`, + 'User-Agent': `Mozilla/5.0 (compatible; UFW-AbuseIPDB-Reporter/${version}; +https://github.com/sefinek/UFW-AbuseIPDB-Reporter)`, 'Accept': 'application/json', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', diff --git a/services/cache.js b/services/cache.js index 0911d27..d2150ee 100644 --- a/services/cache.js +++ b/services/cache.js @@ -1,12 +1,12 @@ -const fs = require('node:fs'); +const { existsSync, readFileSync, writeFileSync } = require('node:fs'); const { CACHE_FILE, IP_REPORT_COOLDOWN } = require('../config.js').MAIN; const log = require('../utils/log.js'); const reportedIPs = new Map(); const loadReportedIPs = () => { - if (fs.existsSync(CACHE_FILE)) { - fs.readFileSync(CACHE_FILE, 'utf8') + if (existsSync(CACHE_FILE)) { + readFileSync(CACHE_FILE, 'utf8') .split('\n') .forEach(line => { const [ip, time] = line.split(' '); @@ -18,7 +18,7 @@ const loadReportedIPs = () => { } }; -const saveReportedIPs = () => fs.writeFileSync(CACHE_FILE, Array.from(reportedIPs).map(([ip, time]) => `${ip} ${time}`).join('\n'), 'utf8'); +const saveReportedIPs = () => writeFileSync(CACHE_FILE, Array.from(reportedIPs).map(([ip, time]) => `${ip} ${time}`).join('\n'), 'utf8'); const isIPReportedRecently = ip => { const reportedTime = reportedIPs.get(ip); diff --git a/services/updates.js b/services/updates.js new file mode 100644 index 0000000..d353d82 --- /dev/null +++ b/services/updates.js @@ -0,0 +1,29 @@ +const { AUTO_UPDATE_SCHEDULE } = require('../config.js').MAIN; + +const simpleGit = require('simple-git'); +const { CronJob } = require('cron'); +const restartApp = require('./reloadApp.js'); +const log = require('../utils/log.js'); + +const git = simpleGit(); + +const pull = async () => { + log(0, '$ git pull'); + + const { summary } = await git.pull(); + log(0, `Changes: ${summary.changes}; Deletions: ${summary.insertions}; Insertions: ${summary.insertions};`); +}; + +const pullAndRestart = async () => { + try { + await pull(); + await restartApp(); + } catch (err) { + log(2, err.message); + } +}; + +// https://crontab.guru +new CronJob(AUTO_UPDATE_SCHEDULE || '0 18 * * *', pullAndRestart, null, true, 'UTC'); // At 18:00 + +module.exports = { pull }; \ No newline at end of file diff --git a/update.js b/update.js deleted file mode 100644 index 997f9c1..0000000 --- a/update.js +++ /dev/null @@ -1,28 +0,0 @@ -const { SERVER_ID, AUTO_UPDATE_SCHEDULE, AUTO_UPDATE_ENABLED } = require('./config.js').MAIN; - -if (AUTO_UPDATE_ENABLED) { - const simpleGit = require('simple-git'); - const { CronJob } = require('cron'); - const restartApp = require('./services/reloadApp.js'); - const log = require('./utils/log.js'); - - const git = simpleGit(); - - const updateScript = async () => { - log(0, 'The script is being updated...'); - - try { - const { summary } = await git.pull(); - log(0, `Changes: ${summary.changes}; Deletions: ${summary.insertions}; Insertions: ${summary.insertions};`); - - if (SERVER_ID !== 'development') await restartApp(); - } catch (err) { - log(2, err.message); - } - }; - - // https://crontab.guru - new CronJob(AUTO_UPDATE_SCHEDULE || '0 18 * * *', updateScript, null, true, 'UTC'); // At 18:00 - - if (SERVER_ID === 'development') (async () => updateScript())(); -} \ No newline at end of file From 6734d087c93a170a983db92d70e31d62ee5efa0e Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 1 Feb 2025 20:30:42 +0100 Subject: [PATCH 112/114] 0.1.2 --- default.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.config.js b/default.config.js index cb42edb..3ac4972 100644 --- a/default.config.js +++ b/default.config.js @@ -2,7 +2,7 @@ exports.MAIN = { // This server UFW_LOG_FILE: '/var/log/ufw.log', CACHE_FILE: '/tmp/ufw-abuseipdb-reporter.cache', - SERVER_ID: null, // The server name that will be visible in the reports (e.g., 'homeserver01'). If you don't want to define it, leave the value as null. + SERVER_ID: null, // The server name that will be visible in the reports (e.g., 'homeserver1'). If you don't want to define it, leave the value as null. REFRESHING_IP_ADDRESS: 5 * 60 * 1000, // How often should (every 5 minutes) the script check the server's IP address to avoid accidental self-reports? // Reporting From 231b3706361f7a881594a6d98e88a68ef0d5e5a0 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 1 Feb 2025 20:31:26 +0100 Subject: [PATCH 113/114] 0.1.2 --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index bcbb9de..d4b1a79 100644 --- a/install.sh +++ b/install.sh @@ -237,7 +237,7 @@ echo -e "\n🎉 Installation and configuration completed! Use the 'pm2 logs' com echo -e "\n====================================== Summary ======================================" echo "🖥️ Server ID : ${server_id:-null}" -echo "🔑 API Token : $api_token" +echo "🔑 API Key : $api_token" echo "📂 Script : $PWD" echo "⚙️ Config File : $PWD/config.js" From d1b991f6639cd457c427c4fc73ecbd34007b3c55 Mon Sep 17 00:00:00 2001 From: Sefinek Date: Sat, 1 Feb 2025 20:32:27 +0100 Subject: [PATCH 114/114] Update install.sh --- install.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/install.sh b/install.sh index d4b1a79..30fcb5b 100644 --- a/install.sh +++ b/install.sh @@ -202,10 +202,6 @@ sudo chown "$USER":"$USER" /var/log/ufw-abuseipdb -R echo "🔒 Changing permissions for $ufw_log_path..." sudo chmod 644 "$ufw_log_path" -# Uninstall corepack -echo "🗑️ Uninstalling corepack..." -sudo npm uninstall corepack -g -silent - # Install pm2 echo "📦 Installing PM2..." sudo npm install pm2 -g -silent