diff options
| author | Jan Tuomi <jan@jantuomi.fi> | 2025-12-29 23:16:22 +0200 |
|---|---|---|
| committer | Jan Tuomi <jan@jantuomi.fi> | 2025-12-29 23:16:22 +0200 |
| commit | 533bc95c751337d5f2952252b0378848cf078357 (patch) | |
| tree | 2bf4ccadc31baf02d2a586fe7357af99787265dc /templates/ingress/pf-ban-socket.py | |
| parent | 39feba1c79c1a0c2743932af35e157ba29d089d1 (diff) | |
Add crawler tarpit
Diffstat (limited to 'templates/ingress/pf-ban-socket.py')
| -rw-r--r-- | templates/ingress/pf-ban-socket.py | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/templates/ingress/pf-ban-socket.py b/templates/ingress/pf-ban-socket.py new file mode 100644 index 0000000..cbcd80e --- /dev/null +++ b/templates/ingress/pf-ban-socket.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +import http.server +import os +import re +import socketserver +import subprocess + +SOCK_PATH = "/var/run/pfban/ban.sock" +PF_TABLE = "blocked" + +# Simple, conservative filter to avoid junk / injection +IP_RE = re.compile(r"^[0-9A-Fa-f:.]{3,}$") + + +def ensure_socket_dir(path: str) -> None: + os.makedirs(os.path.dirname(path), mode=0o755, exist_ok=True) + + +class BanHandler(http.server.BaseHTTPRequestHandler): + # Silence default logging + def log_message(self, format, *args): + return + + def do_POST(self): + if self.path != "/ban": + self.send_response(404) + self.end_headers() + return + + ip = self.headers.get("X-IP", "").strip() + + if ip and IP_RE.match(ip): + subprocess.run( + ["/sbin/pfctl", "-t", PF_TABLE, "-T", "add", ip], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=False, + ) + + self.send_response(204) + self.end_headers() + + def do_GET(self): + self.send_response(405) + self.end_headers() + + +class ThreadingUnixHTTPServer( + socketserver.ThreadingMixIn, + socketserver.UnixStreamServer, +): + daemon_threads = True + + +def main() -> None: + ensure_socket_dir(SOCK_PATH) + + # Remove stale socket if present + try: + os.unlink(SOCK_PATH) + except FileNotFoundError: + pass + + with ThreadingUnixHTTPServer(SOCK_PATH, BanHandler) as httpd: + # Allow nginx workers (www) to connect + os.chmod(SOCK_PATH, 0o660) + + httpd.serve_forever() + + +if __name__ == "__main__": + main() |
