| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 | 
							- #!/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 (Tor 0.1.0.x and earlier):
 
-     python exitlist 18.244.0.188:80 < ~/.tor/cached-directory
 
-  example usage (Tor 0.1.1.10-alpha and later):
 
-     cat ~/.tor/cached-routers* | python exitlist 18.244.0.188:80
 
-  If you're using Tor 0.1.1.18-rc or later, you should look at
 
-  the "FetchUselessDescriptors" config option 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, since some Tor servers might exit
 
-  from other addresses than the one they publish.
 
- """
 
- #
 
- # 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
 
- 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 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
 
-     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
 
-     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()
 
 
  |