Initial commit

This commit is contained in:
2026-02-13 00:30:12 +01:00
commit 322ee99666
7 changed files with 215 additions and 0 deletions

120
autoban.mjs Normal file
View File

@@ -0,0 +1,120 @@
import { readFileSync, realpathSync } from 'node:fs';
import { parse_socket_state } from './parser.mjs';
import { spawn } from 'node:child_process';
// Configuration
const network_interface = 'ens3';
const update_frequency = 1; // Hz
const seen_threshold = 5; // times
const max_age = 20; // seconds
const max_ban_time = 300; // seconds
const dry_run = true;
// Use IGNORE_IPS in environment for comma separated list of IPs that will never be banned
const ignore_ips = new Set(process.env.IGNORE_IPS?.split(',').map(e => e.trim()));
// Application
const peer_map = new Map();
const ban_map = new Map();
const ban_script = realpathSync('./ban.sh');
const unban_script = realpathSync('./unban.sh');
function sudo(argv) {
if (dry_run) {
console.log('sudo', ['-n', ...argv]);
} else {
spawn('sudo', ['-n', ...argv], { stdio: 'inherit', detached: true });
}
}
function ban(ip) {
const ts = performance.now();
if (ignore_ips.has(ip)) {
return;
}
const existing = ban_map.get(ip);
if (existing) {
existing.ts = ts;
} else {
ban_map.set(ip, { ip, ts });
console.log(new Date().toISOString(), '**BAN**', ip);
sudo([ban_script, network_interface, ip]);
}
}
function check_ban_list() {
const ts = performance.now();
for (const entry of ban_map.values()) {
const age = (ts - entry.ts) / 1000;
if (age > max_ban_time) {
ban_map.delete(entry.ip);
console.log(new Date().toISOString(), 'UNBAN', entry.ip);
sudo([unban_script, network_interface, ip]);
}
}
}
function run_at_rate(rate, cb) {
let monotime = performance.now();
function run_once() {
monotime += 1000 / rate;
cb();
const remaining = Math.max(0, monotime - performance.now());
setTimeout(run_once, remaining);
}
run_once();
}
run_at_rate(update_frequency, () => {
// Update once
const socket_state = readFileSync('/proc/net/tcp', 'utf-8');
for (const entry of parse_socket_state(socket_state)) {
if ((entry.st & 0x3) === 0x3) {
const ts = performance.now();
const existing = peer_map.get(entry.rem_address);
if (existing) {
existing.count++;
existing.ts = ts;
} else {
peer_map.set(entry.rem_address, { entry, ts, count: 1 });
console.log(new Date().toISOString(), 'ADD', entry.rem_address);
}
}
}
// Purge old
const ts = performance.now();
for (const entry of peer_map.values()) {
const age = (ts - entry.ts) / 1000;
if (age > max_age) {
peer_map.delete(entry.entry.rem_address);
console.log(new Date().toISOString(), 'DROP', entry.entry.rem_address);
}
}
// Check limits
for (const entry of peer_map.values()) {
if (entry.count > seen_threshold) {
ban(entry.entry.rem_address);
}
}
check_ban_list();
});

1
ban.sh Normal file
View File

@@ -0,0 +1 @@
iptables-nft -C INPUT -i "$1" -s "$2" -j DROP 2>/dev/null || iptables-nft -A INPUT -i "$1" -s "$2" -j DROP

9
notes.txt Normal file
View File

@@ -0,0 +1,9 @@
sudo chown root:root /usr/local/bin/ban.sh /usr/local/bin/unban.sh
sudo chmod 700 /usr/local/bin/ban.sh /usr/local/bin/unban.sh # only root can edit
sudo chattr +i /usr/local/bin/ban.sh /usr/local/bin/unban.sh # make files immutable
sudoers:
ubuntu ALL=(root) NOPASSWD: /home/ubuntu/Projekt/ids/ban.sh, /home/ubuntu/Projekt/ids/unban.sh

42
parser.mjs Normal file
View File

@@ -0,0 +1,42 @@
export function parse_ipv4(value) {
const D = parseInt(value.slice(0, 2), 16);
const C = parseInt(value.slice(2, 4), 16);
const B = parseInt(value.slice(4, 6), 16);
const A = parseInt(value.slice(6, 8), 16);
return `${A}.${B}.${C}.${D}`;
}
export function parse_socket_state(socket_state) {
const ss_lines = socket_state.split('\n').map(line => line.trim());
const fields = ss_lines[0].split(/\s+/);
const result = [];
const field_parsers = {
'st': (value => parseInt(value, 16)),
'local_address': parse_ipv4,
'rem_address': parse_ipv4,
};
for (const line of ss_lines.slice(1)) {
const values = line.split(/\s+/);
const v_iter = values[Symbol.iterator]();
const pending = {};
for (const column of fields.slice(0, -1)) {
pending[column] = v_iter.next().value;
}
pending[fields.at(-1)] = [...v_iter].join(' ');
for (const [name, parser] of Object.entries(field_parsers)) {
const local_value = pending[name];
if (local_value) {
pending[name] = parser(local_value);
}
}
result.push(pending);
}
return result;
}

39
sample-proc-net-tcp.txt Normal file
View File

@@ -0,0 +1,39 @@
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 01234560:0050 01234560:0000 0A 00000000:00000000 00:00000000 00000000 0 0 42854 1 0000000000000000 100 0 0 10 0
1: 01234560:0016 01234560:0000 0A 00000000:00000000 00:00000000 00000000 0 0 60668 1 0000000000000000 100 0 0 10 0
2: 01234560:01BB 01234560:0000 0A 00000000:00000000 00:00000000 00000000 0 0 42856 26 0000000000000000 100 0 0 10 0
3: 01234560:0B7A 01234560:0000 0A 00000000:00000000 00:00000000 00000000 0 0 21963 1 0000000000000000 100 0 0 10 0
4: 3123456F:0035 01234560:0000 0A 00000000:00000000 00:00000000 00000000 101 0 15827 1 0000000000000000 100 0 0 10 5
5: 0123456F:0CEA 01234560:0000 0A 00000000:00000000 00:00000000 00000000 113 0 23714 1 0000000000000000 100 0 0 10 0
6: 0123456F:0BB8 01234560:0000 0A 00000000:00000000 00:00000000 00000000 0 0 60686 1 0000000000000000 100 0 0 10 0
7: 0123456F:18EB 01234560:0000 0A 00000000:00000000 00:00000000 00000000 114 0 22650 1 0000000000000000 100 0 0 10 0
8: E1234565:01BB F1234561:AAA8 03 00000000:00000000 01:00000B07 00000005 0 0 0 0 0000000000000000
9: E1234565:01BB 41234561:1A9B 03 00000000:00000000 01:0000046E 00000005 0 0 0 0 0000000000000000
10: E1234565:01BB 51234561:FBA9 03 00000000:00000000 01:000003AE 00000004 0 0 0 0 0000000000000000
11: E1234565:01BB 41234561:B82C 03 00000000:00000000 01:00000174 00000003 0 0 0 0 0000000000000000
12: E1234565:01BB 91234561:4541 03 00000000:00000000 01:00000074 00000003 0 0 0 0 0000000000000000
13: E1234565:01BB 61234561:D859 03 00000000:00000000 01:00000347 00000004 0 0 0 0 0000000000000000
14: E1234565:01BB 21234561:1C96 03 00000000:00000000 01:00000274 00000003 0 0 0 0 0000000000000000
15: 0123456F:CB3A 0123456F:0BB8 01 00000000:00000000 00:00000000 00000000 33 0 341759 1 0000000000000000 20 4 30 10 -1
16: E1234565:01BB 81234561:3A2E 03 00000000:00000000 01:00000B6E 00000005 0 0 0 0 0000000000000000
17: E1234565:01BB 21234561:9277 03 00000000:00000000 01:000001D4 00000005 0 0 0 0 0000000000000000
18: 0123456F:0BB8 0123456F:CB3A 01 00000000:00000000 02:0000054D 00000000 0 0 340925 2 0000000000000000 20 4 31 10 -1
19: E1234565:01BB 11234561:77CF 03 00000000:00000000 01:00000B21 00000005 0 0 0 0 0000000000000000
20: E1234565:01BB E1234561:F3AA 03 00000000:00000000 01:000003BA 00000005 0 0 0 0 0000000000000000
21: E1234565:01BB 71234561:4165 03 00000000:00000000 01:00000721 00000005 0 0 0 0 0000000000000000
22: E1234565:01BB 91234561:5A44 03 00000000:00000000 01:00000114 00000004 0 0 0 0 0000000000000000
23: E1234565:01BB D1234561:E389 03 00000000:00000000 01:000003EE 00000005 0 0 0 0 0000000000000000
24: E1234565:01BB 91234561:CF3B 03 00000000:00000000 01:00000000 00000005 0 0 0 0 0000000000000000
25: E1234565:01BB F1234561:B713 03 00000000:00000000 01:00000241 00000003 0 0 0 0 0000000000000000
26: 0123456C:8522 0123456C:0BB8 01 00000000:00000000 02:0000054A 00000000 0 0 340927 2 0000000000000000 20 4 30 10 -1
27: E1234565:01BB 31234561:399F 03 00000000:00000000 01:00000000 00000005 0 0 0 0 0000000000000000
28: E1234565:01BB B1234561:E266 03 00000000:00000000 01:0000055E 00000004 0 0 0 0 0000000000000000
29: E1234565:01BB 61234563:512B 01 00000000:00000000 00:00000000 00000000 33 0 339859 1 0000000000000000 24 4 29 8 7
30: E1234565:01BB D1234561:930C 03 00000000:00000000 01:00000024 00000003 0 0 0 0 0000000000000000
31: E1234565:01BB B1234561:21A3 03 00000000:00000000 01:0000008A 00000003 0 0 0 0 0000000000000000
32: E1234565:0B7A F123456E:759B 01 00000000:00000000 02:000AFBFD 00000000 0 0 368411 4 0000000000000000 23 6 19 10 -1
33: E1234565:01BB 91234561:A9FA 03 00000000:00000000 01:00000650 00000005 0 0 0 0 0000000000000000
34: E1234565:01BB D1234561:92DD 03 00000000:00000000 01:00000637 00000005 0 0 0 0 0000000000000000
35: E1234565:01BB 51234561:D9C3 03 00000000:00000000 01:00000005 00000001 0 0 0 0 0000000000000000
36: E1234565:01BB 91234561:6A2F 03 00000000:00000000 01:00000BEA 00000005 0 0 0 0 0000000000000000
37: E1234565:01BB F1234561:1544 03 00000000:00000000 01:000004D0 00000005 0 0 0 0 0000000000000000

3
setup.sh Normal file
View File

@@ -0,0 +1,3 @@
chmod 700 ban.sh unban.sh
chown root:root ban.sh unban.sh
#chattr +i ban.sh unban.sh # make files immutable

1
unban.sh Normal file
View File

@@ -0,0 +1 @@
iptables-nft -D INPUT -i "$1" -s "$2" -j DROP