Sfoglia il codice sorgente

simple python script to parse directories and find tor nodes that exit to listed nodes/ports. interface could be more polished, but this should do.

svn:r3692
Nick Mathewson 19 anni fa
parent
commit
fc37206df6
1 ha cambiato i file con 241 aggiunte e 0 eliminazioni
  1. 241 0
      contrib/exitlist

+ 241 - 0
contrib/exitlist

@@ -0,0 +1,241 @@
+#!/usr/bin/python
+# Copyright 2005 Nick Mathewson
+# See the LICENSE file in the Tor distribution for licensing information.
+
+"""
+ exitlist -- Given a Tor directory on stdin, lists the Tor servers
+ that accept connections to given addreses.
+
+ example usage:
+
+    python2.2 exitlist < ~/.tor/cached-directory
+"""
+
+# Requires Python 2.2 or later.
+
+#
+# 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.
+#
+ADDRESSES_OF_INTEREST = """
+    192.168.0.1:80
+"""
+
+
+#
+# YOU DO NOT NEED TO EDIT AFTER THIS POINT.
+#
+
+import sys
+import re
+import getopt
+import socket
+import struct
+
+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):
+        self.name = name
+        self.ip = ip
+        self.policy = policy
+
+def run():
+    servers = []
+    policy = []
+    name = ip = None
+    for line in sys.stdin.xreadlines():
+        if line.startswith('router '):
+            if name:
+                servers.append(Server(name, ip, Policy.parseLines(policy)))
+            _, name, ip, rest = line.split(" ", 3)
+            policy = []
+        elif line.startswith('accept ') or line.startswith('reject '):
+            policy.append(line.strip())
+
+    if name:
+        servers.append(Server(name, ip, Policy.parseLines(policy)))
+
+    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))
+
+    accepters, rejecters = [], []
+    for s in servers:
+        for ip,port in targets:
+            if s.policy.accepts(ip,port):
+                accepters.append(s)
+                break
+        else:
+            rejecters.append(s)
+
+    if INVERSE:
+        printlist = rejecters
+    else:
+        printlist = accepters
+
+    if VERBOSE:
+        for s in printlist:
+            print "%s\t%s"%(s.ip,s.name)
+    else:
+        for s in printlist:
+            print s.ip
+
+def _test():
+    import doctest, exitparse
+    return doctest.testmod(exitparse)
+#_test()
+
+run()
+