| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- #!/usr/bin/env python3
- """Post a single abuse report to IRDB.
- Usage:
- IRDB_URL=http://localhost:8081 IRDB_TOKEN=irdb_rep_... \\
- examples/reporters/python.py 203.0.113.42 brute_force '{"url":"/wp-login.php"}'
- The third argument (metadata) is optional and must be valid JSON.
- This script uses only the stdlib (`urllib`); no third-party deps.
- fail2ban-action wrapper (drop into `/etc/fail2ban/action.d/irdb.conf`):
- [Definition]
- actionban = /usr/local/bin/irdb-report.py <ip> brute_force
- '{"jail":"<name>","host":"<ipfailures>"}'
- actionunban = true
- [Init]
- name = default
- `<ip>` and `<name>` are substituted by fail2ban at action time. Set
- IRDB_URL and IRDB_TOKEN in fail2ban's environment (e.g. via
- `/etc/default/fail2ban`).
- """
- from __future__ import annotations
- import json
- import os
- import sys
- import urllib.error
- import urllib.request
- def main(argv: list[str]) -> int:
- if len(argv) < 3:
- print(f"Usage: {argv[0]} <ip> <category> [<metadata-json>]", file=sys.stderr)
- return 64
- ip = argv[1]
- category = argv[2]
- metadata_raw = argv[3] if len(argv) > 3 else "{}"
- try:
- metadata = json.loads(metadata_raw)
- except json.JSONDecodeError as e:
- print(f"metadata must be valid JSON: {e}", file=sys.stderr)
- return 65
- url_base = os.environ.get("IRDB_URL")
- token = os.environ.get("IRDB_TOKEN")
- if not url_base or not token:
- print("IRDB_URL and IRDB_TOKEN must be set", file=sys.stderr)
- return 78
- body = json.dumps({"ip": ip, "category": category, "metadata": metadata}).encode()
- req = urllib.request.Request(
- f"{url_base.rstrip('/')}/api/v1/report",
- data=body,
- method="POST",
- headers={
- "Authorization": f"Bearer {token}",
- "Content-Type": "application/json",
- },
- )
- try:
- with urllib.request.urlopen(req, timeout=10) as resp:
- print(resp.read().decode())
- return 0
- except urllib.error.HTTPError as e:
- print(f"http {e.code}: {e.read().decode(errors='replace')}", file=sys.stderr)
- return 1
- except urllib.error.URLError as e:
- print(f"network error: {e}", file=sys.stderr)
- return 2
- if __name__ == "__main__":
- sys.exit(main(sys.argv))
|