]> gitweb.pimeys.fr Git - scripts-20-100.git/commitdiff
Pour faire du torrent sans se faire détecter
authorVincent Le Gallic <legallic@crans.org>
Sun, 20 Oct 2013 22:17:54 +0000 (00:17 +0200)
committerVincent Le Gallic <legallic@crans.org>
Sun, 20 Oct 2013 22:17:54 +0000 (00:17 +0200)
firewall/block_torrent_ip.py [new file with mode: 0755]

diff --git a/firewall/block_torrent_ip.py b/firewall/block_torrent_ip.py
new file mode 100755 (executable)
index 0000000..450701a
--- /dev/null
@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+#-*- coding: utf-8 -*-
+
+""" Script qui récupère la liste des IP des ayants-droits pour empêcher
+    un utilisateur système de communiquer avec en les ajoutant dans le firewall"""
+
+import urllib
+import re
+import zlib
+import netaddr
+import sys
+import subprocess
+import itertools
+import json
+
+### Configuration
+#: URL de la liste
+source_url = u"http://iblocklist.commiecast.com/f/tagqfxtteucbuldhezkz/bt_level1.gz"
+
+#: Nom d'utilisateur UNIX de l'user qui lance le client torrent
+torrent_username = "vincent"
+
+#: IPs qu'on ne veut surtout pas blacklister
+whitelist = [netaddr.IPAddress("138.231.136.1")]
+
+#: Faut-il parler sur la sortie standard ?
+DEBUG = True
+
+#: Nom de la chaîne créée
+chain_name = "TORRENT"
+
+#: Fichier où sauvegarder la liste des IPs
+memfile = "/root/torrent/blocked_ips.json"
+
+def _get_data():
+    """Récupère le raw de la page de la liste."""
+    if DEBUG:
+        print("Loading page")
+    page = urllib.urlopen(source_url)
+    zip = page.read()
+    if DEBUG:
+        print("Decompressing list")
+    data = zlib.decompress(zip, 15+32)
+    return data
+
+def retrieve_ips(limit=None):
+    """Récupère et parse la liste des IPs."""
+    data = _get_data()
+    lines = data.split("\n")
+    ip_regexp = re.compile(r".*?(?P<debut>(?:\d{1,3}\.){3}\d{1,3})-(?P<fin>(?:\d{1,3}\.){3}\d{1,3})$")
+    ips = []
+    if DEBUG:
+        print("Parsing list")
+    for l in lines:
+        match = ip_regexp.match(l)
+        if match:
+            ips.append([match.groupdict()["debut"], match.groupdict()["fin"]])
+    if limit:
+        return ips[:limit]
+    return ips
+
+def process_ranges(liste):
+    """Convertit la liste de [ip début, ip fin] en liste de cidr (/)."""
+    if DEBUG:
+        print("Converting to CIDRs (this may take some time)")
+    cidrs = []
+    for (i, [deb, fin]) in enumerate(liste):
+        #if not i%1000:
+        #    print "%s/%s" % (i, len(liste))
+        cidrs.append(netaddr.iprange_to_cidrs(deb, fin))
+    cidrs = list(itertools.chain.from_iterable(cidrs))
+    return [str(s) for s in cidrs]
+
+def store_ips(slashes):
+    """Sauvegarde la liste des IPs toute utilisable."""
+    json.dump(slashes, open(memfile, "w"))
+
+def load_ips():
+    """Récupère la liste des IPs précédemment sauvegardée sur le disque."""
+    return json.load(open(memfile))
+
+def update_liste():
+    """Met à jour le fichier contenant la liste des IPs."""
+    ips = retrieve_ips()
+    slashes = process_ranges(ips)
+    store_ips(slashes)
+
+def compute_iptables_rules(slashes):
+    """Fabrique les règles iptables à partir de la liste des IPs."""
+    # On vérifie qu'on ne bloque pas une IP de la whitelist
+    if DEBUG:
+        print("Checking whitelist")
+    remove = []
+    for i in xrange(len(slashes)):
+        for white in whitelist:
+            if white in netaddr.IPNetwork(slashes[i]):
+                remove.append(i)
+                break
+    if remove:
+        print "Ranges contenant une IP whitelistée :"
+        print [str(slashes[i]) for i in remove]
+        remove.reverse()
+        for i in remove:
+            del slashes[i]
+    if DEBUG:
+        print("Generating rules")
+    rules = []
+    for s in slashes:
+        rules.append("-A %s -d %s -j REJECT" % (chain_name, s))
+    return rules
+
+def iptables(params):
+    """Appel à iptables"""
+    proc = subprocess.Popen(["iptables"] + params.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    out, err = proc.communicate()
+    return err
+
+
+def flush():
+    """Nettoie le pare-feu des règles générées par ce script."""
+    if DEBUG:
+        print("Flushing rules")
+    err = iptables("-D OUTPUT -m owner --uid-owner %s -j %s" % (torrent_username, chain_name))
+    err += iptables("-F %s" % (chain_name,))
+    err += iptables("-X %s" % (chain_name,))
+    if DEBUG:
+        sys.stderr.write(err)
+
+def initialize():
+    """Créée les règles de base (indépendantes de la liste d'IPs)."""
+    if DEBUG:
+        print("Adding basic rules")
+#    err = iptables("-N %s" % (chain_name,))
+    err = iptables("-A OUTPUT -m owner --uid-owner %s -j %s" % (torrent_username, chain_name))
+    if DEBUG:
+        sys.stderr.write(err)
+
+def add_rules(rules):
+    """Ajoute les règles computées"""
+    if DEBUG:
+        print("Adding rules")
+    generated = "*filter\n:%s - [0:0]" % chain_name
+    generated += "\n".join(rules)
+    generated += "\nCOMMIT\n"
+    proc = subprocess.Popen(["iptables-restore"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    out, err = proc.communicate(input=generated)
+    if DEBUG:
+        sys.stderr.write(err)
+
+if __name__ == "__main__":
+    if "--debug" in sys.argv:
+        DEBUG = True
+    if "--quiet" in sys.argv:
+        DEBUG = False
+    if len(sys.argv) == 1 or sys.argv[1] == "help" or "-h" in sys.argv:
+        print "Usage : fournir un paramètre update ou start ou stop"
+    elif sys.argv[1] == "update":
+        update_liste()
+    elif sys.argv[1] == "start":
+        slashes = load_ips()
+        rules = compute_iptables_rules(slashes)
+        add_rules(rules)
+        initialize()
+    elif sys.argv[1] == "stop":
+        flush()