Merge branch 'main' of https://github.com/sefinek/UFW-AbuseIPDB-Reporter
This commit is contained in:
commit
e9381204c6
20 files changed
+1056
-559
No files matched your search
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="EslintConfiguration">
|
||||||
|
<custom-configuration-file used="true" path="$PROJECT_DIR$/eslint.config.mjs" />
|
||||||
|
<option name="fix-on-save" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,47 +1,88 @@
|
|||||||
<div align="center">
|
|
||||||
[<a href="README.md">English</a>]
|
|
||||||
[<a href="README_PL.md">Polski</a>]
|
|
||||||
</div>
|
|
||||||
|
|
||||||
# 🛡️ UFW AbuseIPDB Reporter
|
# 🛡️ UFW AbuseIPDB Reporter
|
||||||
A utility designed to analyze UFW firewall logs and report malicious IP addresses to the [AbuseIPDB](https://www.abuseipdb.com) database.
|
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 redundant reporting of the same IP address within a short period, the tool uses a temporary cache file to track previously reported IPs.
|
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.
|
||||||
|
|
||||||
If you like this repository or find it useful, I would greatly appreciate it if you could give it a star ⭐. Thanks a lot!
|
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.
|
||||||
See also this: [sefinek/Cloudflare-WAF-To-AbuseIPDB](https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB)
|
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!
|
||||||
|
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).
|
> - 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
|
## 📋 Requirements
|
||||||
- **Operating System:** Linux with UFW firewall installed and configured.
|
1. [Node.js + npm](https://nodejs.org)
|
||||||
- **AbuseIPDB Account:** An account on the AbuseIPDB service [with a valid API token](https://www.abuseipdb.com/account/api). The API token is required.
|
2. [PM2](https://www.npmjs.com/package/pm2)
|
||||||
- **Installed packages:**
|
3. [Git](https://git-scm.com)
|
||||||
- `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.
|
|
||||||
|
|
||||||
|
|
||||||
## 🧪 Tested operating systems
|
## ✅ Features
|
||||||
- **Ubuntu Server:** 20.04 & 22.04
|
1. A [`config.js`](default.config.js) file enabling easy configuration.
|
||||||
|
2. A simple installer allowing quick integration deployment.
|
||||||
*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).*
|
3. Integration with Discord Webhooks (coming soon):
|
||||||
|
- Alerts in case of script errors
|
||||||
|
- Daily summaries of reported IP addresses
|
||||||
|
4. Automatic updates.
|
||||||
|
|
||||||
## 📥 Installation
|
## 📥 Installation
|
||||||
### curl
|
|
||||||
|
### Automatic (easy & recommenced)
|
||||||
|
#### Via curl
|
||||||
```bash
|
```bash
|
||||||
bash <(curl -s https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/main/install.sh)
|
bash <(curl -fsS https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/install.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
### wget
|
#### Via wget
|
||||||
```bash
|
```bash
|
||||||
bash <(wget -qO- https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/main/install.sh)
|
bash <(wget -qO- https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/node.js/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).
|
### Manually
|
||||||
|
#### 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
|
||||||
|
sudo -E bash nodesource_setup.sh && sudo apt-get install -y nodejs
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Git installation
|
||||||
|
```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
|
||||||
|
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
|
||||||
|
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]
|
||||||
|
pm2 save
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 🗑️ Uninstall the deprecated version if you have it
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 🖥️ Usage
|
## 🖥️ Usage
|
||||||
@@ -51,32 +92,33 @@ 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.
|
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.
|
So don't be surprised if the next day, the number of reports to AbuseIPDB exceeds a thousand.
|
||||||
|
|
||||||
### 🔍 Checking service status
|
### 🔍 Checking logs
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl status abuseipdb-ufw.service
|
pm2 logs ufw-abuseipdb
|
||||||
```
|
```
|
||||||
|
|
||||||
To see the current logs generated by the process, use the command:
|
### 📄 Example reports
|
||||||
```bash
|
#### 1️⃣
|
||||||
journalctl -u abuseipdb-ufw.service -f
|
```text
|
||||||
```
|
Blocked by UFW on homeserver01 [80/tcp]
|
||||||
|
Source port: 23639
|
||||||
|
TTL: 247
|
||||||
|
Packet length: 40
|
||||||
|
TOS: 0x00
|
||||||
|
|
||||||
### 📄 Example report
|
This report was generated by:
|
||||||
```
|
|
||||||
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
|
https://github.com/sefinek/UFW-AbuseIPDB-Reporter
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 2️⃣
|
||||||
|
```text
|
||||||
|
Blocked by UFW on homeserver01 [30049/tcp]. Generated by: https://github.com/sefinek/UFW-AbuseIPDB-Reporter
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 🤝 Development
|
## 🤝 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!
|
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
|
## 🔑 [GPL-3.0 License](LICENSE)
|
||||||
Copyright 2024 © by [Sefinek](https://sefinek.net). All rights reserved. See the [LICENSE](LICENSE) file for more information.
|
Copyright 2024-2025 © by [Sefinek](https://sefinek.net). All rights reserved.
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<div align="center">
|
|
||||||
[<a href="README.md">English</a>]
|
|
||||||
[<a href="README_PL.md">Polski</a>]
|
|
||||||
</div>
|
|
||||||
|
|
||||||
# 🛡️ 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.
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
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., '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
|
||||||
|
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)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) =>
|
||||||
|
`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 was generated by:
|
||||||
|
https://github.com/sefinek/UFW-AbuseIPDB-Reporter`; // Please do not remove this URL; I would be very grateful! Thank you. 💙
|
||||||
|
|
||||||
|
// 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`;
|
||||||
|
|
||||||
|
|
||||||
|
// See: https://www.abuseipdb.com/categories
|
||||||
|
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
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.DETERMINE_CATEGORIES = ({ proto, dpt }) => categories[proto]?.[dpt] || '14'; // Default: Port Scan
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
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',
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
};
|
||||||
@@ -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': ['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': ['warn', 'tab'],
|
||||||
|
'keyword-spacing': 'warn',
|
||||||
|
'max-nested-callbacks': ['error', { max: 4 }],
|
||||||
|
'max-statements-per-line': ['error', { max: 2 }],
|
||||||
|
'no-console': 'off',
|
||||||
|
'no-empty': 'warn',
|
||||||
|
'no-empty-function': 'warn',
|
||||||
|
'no-floating-decimal': 'error',
|
||||||
|
'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': 'warn',
|
||||||
|
'no-unreachable': 'warn',
|
||||||
|
'no-unused-vars': 'warn',
|
||||||
|
'no-use-before-define': ['error', { functions: false, classes: true }],
|
||||||
|
'no-var': 'error',
|
||||||
|
'object-curly-spacing': ['warn', 'always'],
|
||||||
|
'prefer-const': 'error',
|
||||||
|
'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/*'],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2024-2025 (c) by Sefinek All rights reserved.
|
||||||
|
// https://sefinek.net
|
||||||
|
//
|
||||||
|
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const chokidar = require('chokidar');
|
||||||
|
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/fetchServerIP.js');
|
||||||
|
const config = require('./config.js');
|
||||||
|
const { version } = require('./package.json');
|
||||||
|
const { UFW_LOG_FILE, ABUSEIPDB_API_KEY, SERVER_ID, AUTO_UPDATE_ENABLED } = config.MAIN;
|
||||||
|
|
||||||
|
let fileOffset = 0;
|
||||||
|
|
||||||
|
const reportToAbuseIPDb = async (logData, categories, comment) => {
|
||||||
|
try {
|
||||||
|
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: ${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)}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const processLogLine = async line => {
|
||||||
|
if (!line.includes('[UFW BLOCK]')) return log(1, `Ignoring line: ${line}`);
|
||||||
|
|
||||||
|
const timestampMatch = line.match(/\[(\d+\.\d+)\]/);
|
||||||
|
const logData = {
|
||||||
|
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,
|
||||||
|
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;
|
||||||
|
if (!srcIp) {
|
||||||
|
log(1, `Missing SRC in log line: ${line}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverAddress().includes(srcIp)) {
|
||||||
|
log(0, `Ignoring own IP address: ${srcIp}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLocalIP(srcIp)) {
|
||||||
|
log(0, `Ignoring local/private IP: ${srcIp}`);
|
||||||
|
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);
|
||||||
|
|
||||||
|
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, `${srcIp} was last reported on ${new Date(lastReportedTime * 1000).toLocaleString()} (${timeAgo} ago)`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const categories = config.DETERMINE_CATEGORIES(logData);
|
||||||
|
const comment = config.REPORT_COMMENT(logData, line, SERVER_ID);
|
||||||
|
|
||||||
|
if (await reportToAbuseIPDb(logData, categories, comment)) {
|
||||||
|
markIPAsReported(srcIp);
|
||||||
|
saveReportedIPs();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
log(0, `v${version} (https://github.com/sefinek/UFW-AbuseIPDB-Reporter)`);
|
||||||
|
|
||||||
|
loadReportedIPs();
|
||||||
|
|
||||||
|
if (!fs.existsSync(UFW_LOG_FILE)) {
|
||||||
|
log(2, `Log file ${UFW_LOG_FILE} does not exist.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileOffset = fs.statSync(UFW_LOG_FILE).size;
|
||||||
|
|
||||||
|
chokidar.watch(UFW_LOG_FILE, { persistent: true, ignoreInitial: true })
|
||||||
|
.on('change', path => {
|
||||||
|
const stats = fs.statSync(path);
|
||||||
|
if (stats.size < fileOffset) {
|
||||||
|
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 => {
|
||||||
|
chunk.split('\n').filter(line => line.trim()).forEach(processLogLine);
|
||||||
|
}).on('end', () => {
|
||||||
|
fileOffset = stats.size;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process?.send) process.send('ready');
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
})();
|
||||||
+193
-211
@@ -1,12 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
###
|
##################################################################
|
||||||
# https://github.com/sefinek/UFW-AbuseIPDB-Reporter
|
# Copyright 2024-2025 (c) by Sefinek All rights reserved. #
|
||||||
##
|
# https://sefinek.net #
|
||||||
|
##################################################################
|
||||||
VERSION="1.1.2"
|
|
||||||
DATE="20.12.2024"
|
|
||||||
REPO="https://github.com/sefinek/UFW-AbuseIPDB-Reporter"
|
|
||||||
|
|
||||||
cat << "EOF"
|
cat << "EOF"
|
||||||
_ _ ___ ____ ____ ____
|
_ _ ___ ____ ____ ____
|
||||||
@@ -21,241 +18,226 @@ cat << "EOF"
|
|||||||
|_|_| |_|\__\___|\__, |_| \__,_|\__|_|\___/|_| |_|
|
|_|_| |_|\__\___|\__, |_| \__,_|\__|_|\___/|_| |_|
|
||||||
|___/
|
|___/
|
||||||
|
|
||||||
EOF
|
>> Made by sefinek.net || Last update: 18.01.2025 <<
|
||||||
|
|
||||||
cat <<EOF
|
This installer will configure UFW-AbuseIPDB-Reporter, a tool that analyzes UFW logs and
|
||||||
>> Made by sefinek.net || Version: $VERSION [$DATE] <<
|
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
|
||||||
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
|
EOF
|
||||||
|
|
||||||
# Function to download a file using either curl or wget
|
# Function to prompt for a Yes/no answer
|
||||||
download_file() {
|
yes_no_prompt() {
|
||||||
local url="$1"
|
local prompt="$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
|
while true; do
|
||||||
read -rp "$ $question [Yes/no]: " response
|
read -r -p "$prompt [Yes/no]: " answer
|
||||||
case "${response,,}" in
|
case $answer in
|
||||||
yes|y) return 0;;
|
[Yy]*|[Yy]es ) return 0 ;; # Return 0 for Yes
|
||||||
no|n) return 1;;
|
[Nn]*|[Nn]o ) return 1 ;; # Return 1 for No
|
||||||
*) echo "Invalid input. Please answer 'yes' or 'no'."
|
* ) echo "❌ Invalid input. Please answer Yes/no or Y/n." ;;
|
||||||
echo;;
|
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# ========================= CHECK FOR MISSING PACKAGES =========================
|
# Function to check and install missing dependencies
|
||||||
required_packages=(ufw jq openssl)
|
check_dependencies() {
|
||||||
missing_packages=()
|
local dependencies=(curl node git)
|
||||||
|
local missing=()
|
||||||
|
|
||||||
for pkg in "${required_packages[@]}"; do
|
for dependency in "${dependencies[@]}"; do
|
||||||
if ! dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null | grep -q "install ok installed"; then
|
if ! command -v "$dependency" &> /dev/null; then
|
||||||
missing_packages+=("$pkg")
|
missing+=("$dependency")
|
||||||
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
|
else
|
||||||
echo -e "INFO: Existing service will not be removed\n"
|
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
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
# =========================== Prepare installation directory ===========================
|
echo "🚨 Missing dependencies: ${missing[*]}"
|
||||||
install_dir="/usr/local/bin/UFW-AbuseIPDB-Reporter"
|
for dep in "${missing[@]}"; do
|
||||||
script_path="$install_dir/reporter.sh"
|
if yes_no_prompt "📦 Do you want to install $dep?"; then
|
||||||
if [ -d "$install_dir" ]; then
|
case $dep in
|
||||||
echo "INFO: Directory $install_dir already exists. Removing it..."
|
curl ) sudo apt-get install -y curl ;;
|
||||||
if ! sudo rm -rf "$install_dir"; then
|
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 ;;
|
||||||
echo "FAIL: Something went wrong. Failed to remove existing directory $install_dir."
|
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..."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
done
|
||||||
|
else
|
||||||
|
echo "✅ All dependencies are installed"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
echo "INFO: Creating installation directory at $install_dir..."
|
# Check dependencies before proceeding
|
||||||
if ! sudo mkdir -p "$install_dir"; then
|
check_dependencies
|
||||||
echo "FAIL: Something went wrong. Failed to create installation directory."
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo
|
|
||||||
|
|
||||||
|
if [[ $response -eq 200 ]]; then
|
||||||
|
echo "✅ Yay! Token is valid."
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "❌ Invalid token! Please try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# =========================== Prepare reporter.sh script ===========================
|
# Check for UFW log file
|
||||||
GITHUB_URL="https://raw.githubusercontent.com/sefinek/UFW-AbuseIPDB-Reporter/main/reporter.sh"
|
if [[ ! -f /var/log/ufw.log ]]; then
|
||||||
echo "INFO: Downloading reporter.sh from $GITHUB_URL..."
|
read -r -p "🔍 /var/log/ufw.log not found. Please enter the path to your log file: " ufw_log_path
|
||||||
if ! download_file "$GITHUB_URL" "$script_path"; then
|
if [[ -f $ufw_log_path ]]; then
|
||||||
echo "FAIL: Something went wrong while downloading the file from GitHub servers! Maybe try running this script as sudo?"
|
echo "✅ Log file found at $ufw_log_path"
|
||||||
|
else
|
||||||
|
echo "❌ Provided log file path does not exist. Exiting..."
|
||||||
exit 1
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ufw_log_path="/var/log/ufw.log"
|
||||||
|
echo "✅ /var/log/ufw.log exists"
|
||||||
fi
|
fi
|
||||||
echo "INFO: Saved reporter.sh at location $script_path"
|
|
||||||
|
|
||||||
if ! sudo chmod +x "$script_path"; then
|
# Prompt for AbuseIPDB API token
|
||||||
echo "FAIL: Failed to make reporter.sh executable."
|
while true; do
|
||||||
exit 1
|
read -r -p "🔑 Please enter your AbuseIPDB API token: " api_token
|
||||||
fi
|
if validate_token "$api_token"; then
|
||||||
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
|
break
|
||||||
fi
|
fi
|
||||||
|
continue
|
||||||
|
done
|
||||||
|
|
||||||
attempts_left=$((max_attempts - attempts - 1))
|
# Prompt for server ID
|
||||||
if (( attempts_left > 0 )); then
|
while true; do
|
||||||
echo "WARN: Invalid API token format. Please enter an 80-character hexadecimal string. You have $attempts_left/$max_attempts attempts left."
|
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
|
||||||
|
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
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "$valid_token" != true ]]; then
|
# Prompt for system update and upgrade
|
||||||
echo "FAIL: Maximum number of attempts reached. Installation aborted!"
|
if yes_no_prompt "🛠️ Do you want the script to run apt update and apt upgrade for you?"; then
|
||||||
exit 1
|
echo "🔧 Updating and upgrading the system..."
|
||||||
|
sudo apt-get update && sudo apt-get upgrade
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Encode the API token
|
# Clone repository & set permissions
|
||||||
token_file="$install_dir/.abuseipdb_token"
|
if [ ! -d "/opt" ]; then
|
||||||
echo "INFO: Encoding data (file $token_file)..."
|
mkdir -p /opt
|
||||||
if ! echo -n "$api_key" | openssl enc -base64 | sudo tee "$token_file" >/dev/null; then
|
echo "📂 '/opt' has been created"
|
||||||
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
|
else
|
||||||
echo -e "INFO: reporter.sh will not be added as a service. Running the script directly... Press ^C to stop.\n"
|
echo "✅ '/opt' directory already exists"
|
||||||
if "$script_path"; then
|
|
||||||
echo "INFO: reporter.sh executed successfully."
|
|
||||||
else
|
|
||||||
echo "FAIL: Failed to execute reporter.sh!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
echo
|
|
||||||
|
|
||||||
# Prompt to add the service to autostart
|
cd /opt || { echo "❌ Failed to change directory to '/opt'. Exiting..."; exit 1; }
|
||||||
if ask_user "Do you want to add abuseipdb-ufw.service to autostart?"; then
|
|
||||||
if sudo systemctl enable abuseipdb-ufw.service; then
|
if [ ! -d "UFW-AbuseIPDB-Reporter" ]; then
|
||||||
echo "INFO: Great! abuseipdb-ufw.service has been added to autostart. Installation finished!"
|
echo "📥 Cloning the UFW-AbuseIPDB-Reporter repository..."
|
||||||
echo "INFO: Run 'journalctl -u abuseipdb-ufw.service -f' to view more logs."
|
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 "FAIL: Failed to add abuseipdb-ufw.service to autostart!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
echo "INFO: abuseipdb-ufw.service will not be added to autostart. Installation finished!"
|
echo "✨ The UFW-AbuseIPDB-Reporter repository already exists"
|
||||||
fi
|
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
|
||||||
|
|
||||||
|
# Copy configuration file
|
||||||
|
if [ -e config.js ]; then
|
||||||
|
echo "✅ config.js already exists"
|
||||||
|
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"
|
||||||
|
if [[ -f $config_file ]]; then
|
||||||
|
echo "🔧 Updating $PWD/$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
|
||||||
|
echo "❌ $config_file not found. Make sure the repository was cloned and initialized correctly."
|
||||||
|
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"
|
||||||
|
|
||||||
|
# Install pm2
|
||||||
|
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 "⚙️ 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."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "⚙️ Running a script with PM2 and saving the current state of all processes managed by it..."
|
||||||
|
pm2 start --silent
|
||||||
|
pm2 save --silent
|
||||||
|
|
||||||
|
|
||||||
|
# Final
|
||||||
|
echo "🌌 Checking PM2 status..."
|
||||||
|
pm2 status
|
||||||
|
|
||||||
|
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}"
|
||||||
|
echo "🔑 API Key : $api_token"
|
||||||
|
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"
|
||||||
Generated
+261
@@ -0,0 +1,261 @@
|
|||||||
|
{
|
||||||
|
"name": "ufw-abuseipdb-reporter",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "ufw-abuseipdb-reporter",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
|
"cron": "^3.5.0",
|
||||||
|
"ipaddr.js": "^2.2.0",
|
||||||
|
"simple-git": "^3.27.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.19.0",
|
||||||
|
"globals": "^15.14.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@eslint/js": {
|
||||||
|
"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": {
|
||||||
|
"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",
|
||||||
|
"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/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",
|
||||||
|
"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/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",
|
||||||
|
"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/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",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/readdirp": {
|
||||||
|
"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.18.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "ufw-abuseipdb-reporter",
|
||||||
|
"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",
|
||||||
|
"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 <contact@sefinek.net> (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"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.7.9",
|
||||||
|
"chokidar": "^4.0.3",
|
||||||
|
"cron": "^3.5.0",
|
||||||
|
"ipaddr.js": "^2.2.0",
|
||||||
|
"simple-git": "^3.27.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.19.0",
|
||||||
|
"globals": "^15.14.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
-222
@@ -1,222 +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]+')
|
|
||||||
|
|
||||||
# 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" ]]; then
|
|
||||||
log "INFO" "Skipping UDP traffic: SRC=$src_ip DPT=$dpt"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
const axios = require('axios');
|
||||||
|
const { version } = require('../package.json');
|
||||||
|
|
||||||
|
axios.defaults.headers.common = {
|
||||||
|
'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',
|
||||||
|
};
|
||||||
|
|
||||||
|
axios.defaults.timeout = 30000;
|
||||||
|
|
||||||
|
module.exports = axios;
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
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 (existsSync(CACHE_FILE)) {
|
||||||
|
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 = () => writeFileSync(CACHE_FILE, Array.from(reportedIPs).map(([ip, time]) => `${ip} ${time}`).join('\n'), 'utf8');
|
||||||
|
|
||||||
|
const isIPReportedRecently = ip => {
|
||||||
|
const reportedTime = reportedIPs.get(ip);
|
||||||
|
return reportedTime && (Date.now() / 1000 - reportedTime < IP_REPORT_COOLDOWN / 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
const markIPAsReported = ip => reportedIPs.set(ip, Math.floor(Date.now() / 1000));
|
||||||
|
|
||||||
|
module.exports = { reportedIPs, loadReportedIPs, saveReportedIPs, isIPReportedRecently, markIPAsReported };
|
||||||
@@ -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);
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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 };
|
||||||
@@ -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);
|
||||||
|
};
|
||||||
@@ -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}`);
|
||||||
|
};
|
||||||
Reference in new issue
Block a user