1
0

python.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #!/usr/bin/env python3
  2. """Post a single abuse report to IRDB.
  3. Usage:
  4. IRDB_URL=http://localhost:8081 IRDB_TOKEN=irdb_rep_... \\
  5. examples/reporters/python.py 203.0.113.42 brute_force '{"url":"/wp-login.php"}'
  6. The third argument (metadata) is optional and must be valid JSON.
  7. This script uses only the stdlib (`urllib`); no third-party deps.
  8. fail2ban-action wrapper (drop into `/etc/fail2ban/action.d/irdb.conf`):
  9. [Definition]
  10. actionban = /usr/local/bin/irdb-report.py <ip> brute_force
  11. '{"jail":"<name>","host":"<ipfailures>"}'
  12. actionunban = true
  13. [Init]
  14. name = default
  15. `<ip>` and `<name>` are substituted by fail2ban at action time. Set
  16. IRDB_URL and IRDB_TOKEN in fail2ban's environment (e.g. via
  17. `/etc/default/fail2ban`).
  18. """
  19. from __future__ import annotations
  20. import json
  21. import os
  22. import sys
  23. import urllib.error
  24. import urllib.request
  25. def main(argv: list[str]) -> int:
  26. if len(argv) < 3:
  27. print(f"Usage: {argv[0]} <ip> <category> [<metadata-json>]", file=sys.stderr)
  28. return 64
  29. ip = argv[1]
  30. category = argv[2]
  31. metadata_raw = argv[3] if len(argv) > 3 else "{}"
  32. try:
  33. metadata = json.loads(metadata_raw)
  34. except json.JSONDecodeError as e:
  35. print(f"metadata must be valid JSON: {e}", file=sys.stderr)
  36. return 65
  37. url_base = os.environ.get("IRDB_URL")
  38. token = os.environ.get("IRDB_TOKEN")
  39. if not url_base or not token:
  40. print("IRDB_URL and IRDB_TOKEN must be set", file=sys.stderr)
  41. return 78
  42. body = json.dumps({"ip": ip, "category": category, "metadata": metadata}).encode()
  43. req = urllib.request.Request(
  44. f"{url_base.rstrip('/')}/api/v1/report",
  45. data=body,
  46. method="POST",
  47. headers={
  48. "Authorization": f"Bearer {token}",
  49. "Content-Type": "application/json",
  50. },
  51. )
  52. try:
  53. with urllib.request.urlopen(req, timeout=10) as resp:
  54. print(resp.read().decode())
  55. return 0
  56. except urllib.error.HTTPError as e:
  57. print(f"http {e.code}: {e.read().decode(errors='replace')}", file=sys.stderr)
  58. return 1
  59. except urllib.error.URLError as e:
  60. print(f"network error: {e}", file=sys.stderr)
  61. return 2
  62. if __name__ == "__main__":
  63. sys.exit(main(sys.argv))