|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# Update by Deniz version 3.x |
| 3 | + |
| 4 | +from subprocess import call, check_call, CalledProcessError |
| 5 | +from os.path import isfile, basename |
| 6 | +from os import devnull |
| 7 | +from sys import exit, stdout, stderr |
| 8 | +from atexit import register |
| 9 | +from argparse import ArgumentParser |
| 10 | +from json import load |
| 11 | +from urllib.request import urlopen |
| 12 | +from urllib.error import URLError |
| 13 | +from time import sleep |
| 14 | +import subprocess |
| 15 | +import requests |
| 16 | + |
| 17 | +class PrivacyNet(object): |
| 18 | + |
| 19 | + def __init__(self): |
| 20 | + self.local_dnsport = "53" # DNSPort |
| 21 | + self.virtual_net = "10.0.0.0/10" # VirtualAddrNetwork |
| 22 | + self.local_loopback = "127.0.0.1" # Local loopback |
| 23 | + self.non_tor_net = ["192.168.0.0/16", "172.16.0.0/12"] |
| 24 | + self.non_tor = ["127.0.0.0/9", "127.128.0.0/10", "127.0.0.0/8"] |
| 25 | + self.tor_uid = subprocess.getoutput("id -ur debian-tor") # Tor user uid |
| 26 | + self.trans_port = "9040" # Tor port |
| 27 | + self.tor_config_file = '/etc/tor/torrc' |
| 28 | + self.torrc = r''' |
| 29 | +## Inserted by %s for tor iptables rules set |
| 30 | +## Transparently route all traffic thru tor on port %s |
| 31 | +VirtualAddrNetwork %s |
| 32 | +AutomapHostsOnResolve 1 |
| 33 | +TransPort %s |
| 34 | +DNSPort %s |
| 35 | +''' % (basename(__file__), self.trans_port, self.virtual_net, self.trans_port, self.local_dnsport) |
| 36 | + |
| 37 | + def geolocate_ip(self, ip): |
| 38 | + try: |
| 39 | + response = requests.get(f"http://ip-api.com/json/{ip}") |
| 40 | + data = response.json() |
| 41 | + country = data["country"] |
| 42 | + city = data["city"] |
| 43 | + return country, city |
| 44 | + except Exception as e: |
| 45 | + print(f"Error geolocating IP: {e}") |
| 46 | + return None, None |
| 47 | + |
| 48 | + def flush_iptables_rules(self): |
| 49 | + call(["iptables", "-F"]) |
| 50 | + call(["iptables", "-t", "nat", "-F"]) |
| 51 | + |
| 52 | + def load_iptables_rules(self): |
| 53 | + self.flush_iptables_rules() |
| 54 | + self.non_tor.extend(self.non_tor_net) |
| 55 | + |
| 56 | + @register |
| 57 | + def restart_tor(): |
| 58 | + fnull = open(devnull, 'w') |
| 59 | + try: |
| 60 | + tor_restart = check_call( |
| 61 | + ["service", "tor", "restart"], |
| 62 | + stdout=fnull, stderr=fnull) |
| 63 | + |
| 64 | + if tor_restart == 0: |
| 65 | + print(" {0}".format( |
| 66 | + "[+] Anonymizer status [ON]")) |
| 67 | + self.get_ip() |
| 68 | + except CalledProcessError as err: |
| 69 | + print("[!] Command failed: %s" % ' '.join(err.cmd)) |
| 70 | + |
| 71 | + # See https://trac.torproject.org/projects/tor/wiki/doc/TransparentProxy#WARNING |
| 72 | + # See https://lists.torproject.org/pipermail/tor-talk/2014-March/032503.html |
| 73 | + call(["iptables", "-I", "OUTPUT", "!", "-o", "lo", "!", "-d",self.local_loopback, "!", "-s", self.local_loopback, "-p", "tcp","-m", "tcp", "--tcp-flags", "ACK,FIN", "ACK,FIN", "-j", "DROP"]) |
| 74 | + call(["iptables", "-I", "OUTPUT", "!", "-o", "lo", "!", "-d",self.local_loopback, "!", "-s", self.local_loopback, "-p", "tcp","-m", "tcp", "--tcp-flags", "ACK,RST", "ACK,RST", "-j", "DROP"]) |
| 75 | + call(["iptables", "-t", "nat", "-A", "OUTPUT", "-m", "owner", "--uid-owner","%s" % self.tor_uid, "-j", "RETURN"]) |
| 76 | + call(["iptables", "-t", "nat", "-A", "OUTPUT", "-p", "udp", "--dport",self.local_dnsport, "-j", "REDIRECT", "--to-ports", self.local_dnsport]) |
| 77 | + |
| 78 | + for net in self.non_tor: |
| 79 | + call(["iptables", "-t", "nat", "-A", "OUTPUT", "-d", "%s" % net, "-j","RETURN"]) |
| 80 | + |
| 81 | + call(["iptables", "-t", "nat", "-A", "OUTPUT", "-p", "tcp", "--syn", "-j","REDIRECT", "--to-ports", "%s" % self.trans_port]) |
| 82 | + call(["iptables", "-A", "OUTPUT", "-m", "state", "--state","ESTABLISHED,RELATED", "-j", "ACCEPT"]) |
| 83 | + for net in self.non_tor: |
| 84 | + call(["iptables", "-A", "OUTPUT", "-d", "%s" % net, "-j", "ACCEPT"]) |
| 85 | + |
| 86 | + call(["iptables", "-A", "OUTPUT", "-m", "owner", "--uid-owner", "%s" % self.tor_uid, "-j", "ACCEPT"]) |
| 87 | + call(["iptables", "-A", "OUTPUT", "-j", "REJECT"]) |
| 88 | + |
| 89 | + def get_ip(self): |
| 90 | + print(" {0}".format("[\033[92m*\033[0m] Getting public IP, please wait...")) |
| 91 | + retries = 0 |
| 92 | + my_public_ip = None |
| 93 | + while retries < 12 and not my_public_ip: |
| 94 | + retries += 1 |
| 95 | + try: |
| 96 | + my_public_ip = load(urlopen('https://check.torproject.org/api/ip'))['IP'] |
| 97 | + except URLError: |
| 98 | + sleep(5) |
| 99 | + print(" [\033[93m?\033[0m] Still waiting for IP address...") |
| 100 | + except ValueError: |
| 101 | + break |
| 102 | + if not my_public_ip: |
| 103 | + my_public_ip = subprocess.getoutput('wget -qO - ifconfig.me') |
| 104 | + if not my_public_ip: |
| 105 | + exit(" \033[91m[!]\033[0m Can't get public ip address!") |
| 106 | + |
| 107 | + country, city = self.geolocate_ip(my_public_ip) |
| 108 | + if country and city: |
| 109 | + print(" {0}".format("[\033[92m+\033[0m] Your IP is \033[92m%s\033[0m" % my_public_ip)) |
| 110 | + print(" {0}".format("[\033[92m+\033[0m] Country: \033[92m%s\033[0m" % country)) |
| 111 | + print(" {0}".format("[\033[92m+\033[0m] City: \033[92m%s\033[0m" % city)) |
| 112 | + else: |
| 113 | + print(" {0}".format("[\033[92m+\033[0m] Your IP is \033[92m%s\033[0m" % my_public_ip)) |
| 114 | + print(" {0}".format("[\033[93m!\033[0m] Error geolocating IP")) |
| 115 | + |
| 116 | + |
| 117 | +if __name__ == '__main__': |
| 118 | + parser = ArgumentParser( |
| 119 | + description='Tor Iptables script for loading and unloading iptables rules') |
| 120 | + parser.add_argument('-l','--load', action='store_true', help='This option will load tor iptables rules') |
| 121 | + parser.add_argument('-f', '--flush',action='store_true', help='This option flushes the iptables rules to default') |
| 122 | + parser.add_argument('-r','--refresh', action='store_true', help='This option will change the circuit and gives new IP') |
| 123 | + parser.add_argument('-i', '--ip', action='store_true', help='This option will output the current public IP address') |
| 124 | + args = parser.parse_args() |
| 125 | + |
| 126 | + try: |
| 127 | + load_tables = PrivacyNet() |
| 128 | + if isfile(load_tables.tor_config_file): |
| 129 | + if not 'VirtualAddrNetwork' in open(load_tables.tor_config_file).read(): |
| 130 | + with open(load_tables.tor_config_file, 'a+') as torrconf: |
| 131 | + torrconf.write(load_tables.torrc) |
| 132 | + |
| 133 | + if args.load: |
| 134 | + load_tables.load_iptables_rules() |
| 135 | + elif args.flush: |
| 136 | + load_tables.flush_iptables_rules() |
| 137 | + print(" {0}".format("[\033[93m!\033[0m] Anonymizer status \033[91m[OFF]\033[0m")) |
| 138 | + elif args.ip: |
| 139 | + load_tables.get_ip() |
| 140 | + elif args.refresh: |
| 141 | + call(['kill', '-HUP', '%s' % subprocess.getoutput('pidof tor')]) |
| 142 | + load_tables.get_ip() |
| 143 | + else: |
| 144 | + parser.print_help() |
| 145 | + except Exception as err: |
| 146 | + print(f"[!] Run as super user: {err[1]}") |
| 147 | + |
0 commit comments