diff options
Diffstat (limited to 'contrib/exitlist')
-rwxr-xr-x | contrib/exitlist | 323 |
1 files changed, 0 insertions, 323 deletions
diff --git a/contrib/exitlist b/contrib/exitlist deleted file mode 100755 index 3fd26b5166..0000000000 --- a/contrib/exitlist +++ /dev/null @@ -1,323 +0,0 @@ -#!/usr/bin/python -# Copyright 2005-2006 Nick Mathewson -# See the LICENSE file in the Tor distribution for licensing information. - -# Requires Python 2.2 or later. - -""" - exitlist -- Given a Tor directory on stdin, lists the Tor servers - that accept connections to given addreses. - - example usage: - - cat ~/.tor/cached-descriptors* | python exitlist 18.244.0.188:80 - - You should look at the "FetchUselessDescriptors" and "FetchDirInfoEarly" - config options in the man page. - - Note that this script won't give you a perfect list of IP addresses - that might connect to you using Tor. - False negatives: - - Some Tor servers might exit from other addresses than the one they - publish in their descriptor. - False positives: - - This script just looks at the descriptor lists, so it counts relays - that were running a day in the past and aren't running now (or are - now running at a different address). - - See https://check.torproject.org/ for an alternative (more accurate!) - approach. - -""" - -# -# Change this to True if you want more verbose output. By default, we -# only print the IPs of the servers that accept any the listed -# addresses, one per line. -# -VERBOSE = False - -# -# Change this to True if you want to reverse the output, and list the -# servers that accept *none* of the listed addresses. -# -INVERSE = False - -# -# Change this list to contain all of the target services you are interested -# in. It must contain one entry per line, each consisting of an IPv4 address, -# a colon, and a port number. This default is only used if we don't learn -# about any addresses from the command-line. -# -ADDRESSES_OF_INTEREST = """ - 1.2.3.4:80 -""" - - -# -# YOU DO NOT NEED TO EDIT AFTER THIS POINT. -# - -import sys -import re -import getopt -import socket -import struct -import time - -assert sys.version_info >= (2,2) - - -def maskIP(ip,mask): - return "".join([chr(ord(a) & ord(b)) for a,b in zip(ip,mask)]) - -def maskFromLong(lng): - return struct.pack("!L", lng) - -def maskByBits(n): - return maskFromLong(0xffffffffl ^ ((1L<<(32-n))-1)) - -class Pattern: - """ - >>> import socket - >>> ip1 = socket.inet_aton("192.169.64.11") - >>> ip2 = socket.inet_aton("192.168.64.11") - >>> ip3 = socket.inet_aton("18.244.0.188") - - >>> print Pattern.parse("18.244.0.188") - 18.244.0.188/255.255.255.255:1-65535 - >>> print Pattern.parse("18.244.0.188/16:*") - 18.244.0.0/255.255.0.0:1-65535 - >>> print Pattern.parse("18.244.0.188/2.2.2.2:80") - 2.0.0.0/2.2.2.2:80-80 - >>> print Pattern.parse("192.168.0.1/255.255.00.0:22-25") - 192.168.0.0/255.255.0.0:22-25 - >>> p1 = Pattern.parse("192.168.0.1/255.255.00.0:22-25") - >>> import socket - >>> p1.appliesTo(ip1, 22) - False - >>> p1.appliesTo(ip2, 22) - True - >>> p1.appliesTo(ip2, 25) - True - >>> p1.appliesTo(ip2, 26) - False - """ - def __init__(self, ip, mask, portMin, portMax): - self.ip = maskIP(ip,mask) - self.mask = mask - self.portMin = portMin - self.portMax = portMax - - def __str__(self): - return "%s/%s:%s-%s"%(socket.inet_ntoa(self.ip), - socket.inet_ntoa(self.mask), - self.portMin, - self.portMax) - - def parse(s): - if ":" in s: - addrspec, portspec = s.split(":",1) - else: - addrspec, portspec = s, "*" - - if addrspec == '*': - ip,mask = "\x00\x00\x00\x00","\x00\x00\x00\x00" - elif '/' not in addrspec: - ip = socket.inet_aton(addrspec) - mask = "\xff\xff\xff\xff" - else: - ip,mask = addrspec.split("/",1) - ip = socket.inet_aton(ip) - if "." in mask: - mask = socket.inet_aton(mask) - else: - mask = maskByBits(int(mask)) - - if portspec == '*': - portMin = 1 - portMax = 65535 - elif '-' not in portspec: - portMin = portMax = int(portspec) - else: - portMin, portMax = map(int,portspec.split("-",1)) - - return Pattern(ip,mask,portMin,portMax) - - parse = staticmethod(parse) - - def appliesTo(self, ip, port): - return ((maskIP(ip,self.mask) == self.ip) and - (self.portMin <= port <= self.portMax)) - -class Policy: - """ - >>> import socket - >>> ip1 = socket.inet_aton("192.169.64.11") - >>> ip2 = socket.inet_aton("192.168.64.11") - >>> ip3 = socket.inet_aton("18.244.0.188") - - >>> pol = Policy.parseLines(["reject *:80","accept 18.244.0.188:*"]) - >>> print str(pol).strip() - reject 0.0.0.0/0.0.0.0:80-80 - accept 18.244.0.188/255.255.255.255:1-65535 - >>> pol.accepts(ip1,80) - False - >>> pol.accepts(ip3,80) - False - >>> pol.accepts(ip3,81) - True - """ - - def __init__(self, lst): - self.lst = lst - - def parseLines(lines): - r = [] - for item in lines: - a,p=item.split(" ",1) - if a == 'accept': - a = True - elif a == 'reject': - a = False - else: - raise ValueError("Unrecognized action %r",a) - p = Pattern.parse(p) - r.append((p,a)) - return Policy(r) - - parseLines = staticmethod(parseLines) - - def __str__(self): - r = [] - for pat, accept in self.lst: - rule = accept and "accept" or "reject" - r.append("%s %s\n"%(rule,pat)) - return "".join(r) - - def accepts(self, ip, port): - for pattern,accept in self.lst: - if pattern.appliesTo(ip,port): - return accept - return True - -class Server: - def __init__(self, name, ip, policy, published, fingerprint): - self.name = name - self.ip = ip - self.policy = policy - self.published = published - self.fingerprint = fingerprint - -def uniq_sort(lst): - d = {} - for item in lst: d[item] = 1 - lst = d.keys() - lst.sort() - return lst - -def run(): - global VERBOSE - global INVERSE - global ADDRESSES_OF_INTEREST - - if len(sys.argv) > 1: - try: - opts, pargs = getopt.getopt(sys.argv[1:], "vx") - except getopt.GetoptError, e: - print """ -usage: cat ~/.tor/cached-routers* | %s [-v] [-x] [host:port [host:port [...]]] - -v verbose output - -x invert results -""" % sys.argv[0] - sys.exit(0) - - for o, a in opts: - if o == "-v": - VERBOSE = True - if o == "-x": - INVERSE = True - if len(pargs): - ADDRESSES_OF_INTEREST = "\n".join(pargs) - - servers = [] - policy = [] - name = ip = None - published = 0 - fp = "" - for line in sys.stdin.xreadlines(): - if line.startswith('router '): - if name: - servers.append(Server(name, ip, Policy.parseLines(policy), - published, fp)) - _, name, ip, rest = line.split(" ", 3) - policy = [] - published = 0 - fp = "" - elif line.startswith('fingerprint') or \ - line.startswith('opt fingerprint'): - elts = line.strip().split() - if elts[0] == 'opt': del elts[0] - assert elts[0] == 'fingerprint' - del elts[0] - fp = "".join(elts) - elif line.startswith('accept ') or line.startswith('reject '): - policy.append(line.strip()) - elif line.startswith('published '): - date = time.strptime(line[len('published '):].strip(), - "%Y-%m-%d %H:%M:%S") - published = time.mktime(date) - - if name: - servers.append(Server(name, ip, Policy.parseLines(policy), published, - fp)) - - targets = [] - for line in ADDRESSES_OF_INTEREST.split("\n"): - line = line.strip() - if not line: continue - p = Pattern.parse(line) - targets.append((p.ip, p.portMin)) - - # remove all but the latest server of each IP/Nickname pair. - latest = {} - for s in servers: - if (not latest.has_key((s.fingerprint)) - or s.published > latest[(s.fingerprint)]): - latest[s.fingerprint] = s - servers = latest.values() - - accepters, rejecters = {}, {} - for s in servers: - for ip,port in targets: - if s.policy.accepts(ip,port): - accepters[s.ip] = s - break - else: - rejecters[s.ip] = s - - # If any server at IP foo accepts, the IP does not reject. - for k in accepters.keys(): - if rejecters.has_key(k): - del rejecters[k] - - if INVERSE: - printlist = rejecters.values() - else: - printlist = accepters.values() - - ents = [] - if VERBOSE: - ents = uniq_sort([ "%s\t%s"%(s.ip,s.name) for s in printlist ]) - else: - ents = uniq_sort([ s.ip for s in printlist ]) - for e in ents: - print e - -def _test(): - import doctest, exitparse - return doctest.testmod(exitparse) -#_test() - -run() - |