Ticket #7549: test.py

File test.py, 4.2 KB (added by jct, 7 years ago)

Testing the connection to a Tor instance running in the same host as the Facilitator in order to get a list of Tor Exit nodes.

Line 
1
2import threading
3import socket
4import sys
5
6BUFFER_SIZE = 4096
7TOR_CRLF = '\n'
8TOR_HOST = '127.0.0.1'
9TOR_PORT = 64000
10TOR_PASS = '"aa"'
11TOR_CMD1 = 'AUTHENTICATE ' + TOR_PASS + TOR_CRLF
12TOR_CMD2 = 'GETINFO ns/all' + TOR_CRLF
13TOR_OK1 = '250 OK'
14TOR_OK2 = '250+ns/all='
15TOR_EXIT_NODE = 'Exit'
16TOR_START_LINE_IP = 'r '
17TOR_START_LINE_CODES = 's '
18TOR_IP_POS_LINE = 6
19
20# It is holding the list with the addresses from Tor Exit nodes.
21class TorExitNodesSet(object):
22    def __init__(self):
23        self.set = []
24        self.cv = threading.Condition()
25
26    def replace(self, exit_nodes_tmp):
27        self.cv.acquire()
28        try:
29            self.set = exit_nodes_tmp
30            self.cv.notify()
31        finally:
32            self.cv.release()
33
34    def query(self, exit):
35        self.cv.acquire()
36        try:
37            if (not self.set) or (len(self.set) == 0) or (not (exit in self.set)):
38                return False
39            else:
40                return True
41        finally:
42            self.cv.release()
43
44tor_exit_nodes = TorExitNodesSet()
45
46# It returns a generator capable of reading from a socket the
47# line responses with the Tor Control Protocol 's format.
48def readline(s):
49    buffer = s.recv(BUFFER_SIZE)
50    while True:
51        if TOR_CRLF in buffer:
52            (line, buffer) = buffer.split(TOR_CRLF, 1)
53            yield line
54        else:
55            data = s.recv(BUFFER_SIZE)
56            if data == '':
57                raise RuntimeError("The socket connection is broken")
58            else:
59                buffer = buffer + data
60
61# It returns a TCP socket connection or None.
62def get_conn(ip_ver, host, port):
63   try:
64      # It creates a TCP socket.
65      s = socket.socket(ip_ver, socket.SOCK_STREAM)
66   except socket.error:
67      e = sys.exc_info()[1]
68      s = None
69      print 'Failed to create socket to use with Tor: %s' %(e)
70
71   try:
72      # It connects with Tor.
73      s.connect((host , port))
74   except socket.error:
75      s.close()
76      s = None
77      e = sys.exc_info()[1]
78      print 'Failed to connect with Tor: %s' %(e)
79
80   return s
81
82# It returns a list with the Tor Exit nodes or None.
83# In order to get the list, it communicates with the Tor using the 'Tor Control Protocol'.
84# https://gitweb.torproject.org/torspec.git?a=blob_plain;hb=HEAD;f=control-spec.txt
85def get_tor_info(s):
86   try:
87      replace = False
88      exit_nodes_tmp = None
89
90      lines = readline(s)
91
92      # It authenticates with Tor.
93      s.sendall(TOR_CMD1)
94      line = lines.next()
95
96      if TOR_OK1 in line:
97         # It asks Tor the router status info (v2 directory style)
98         # for all the ORs that Tor have an opinion about.
99         s.sendall(TOR_CMD2)
100
101         # Consume the first line
102         line = lines.next()
103
104         if TOR_OK2 in line:
105            exit_nodes_tmp = []
106            is_v = False
107            for line in lines:
108               if TOR_OK1 in line:
109                  break
110               else:
111                  # Decoding a line with the v2 directory style.
112                  # https://gitweb.torproject.org/torspec.git?a=blob_plain;hb=HEAD;f=dir-spec-v2.txt
113                  if is_v and line.startswith(TOR_START_LINE_CODES):
114                     # It also catches 'BadExit' but is OK.
115                     if TOR_EXIT_NODE in line:
116                        exit_nodes_tmp.append(ip)
117                        is_v = False
118                  elif line.startswith(TOR_START_LINE_IP):
119                     elements = line.split()
120                     ip = elements[TOR_IP_POS_LINE]
121                     is_v = True
122            replace = True
123         else:
124            print "There was a problem with the Tor' answer: %s" %(line)
125      else:
126         print "There was a problem with the Tor authentication: %s" %(line)
127   except Exception:
128      e = sys.exc_info()[1]
129      print 'Failed the communication with Tor: %s' %(e)
130
131   if replace and exit_nodes_tmp is not None:
132      return exit_nodes_tmp
133   else:
134      return None
135
136# TESTING
137s = get_conn(socket.AF_INET, TOR_HOST, TOR_PORT)
138if s is not None:
139   exit_nodes_tmp = get_tor_info(s)
140   if exit_nodes_tmp is not None:
141      tor_exit_nodes.replace(exit_nodes_tmp)
142      print tor_exit_nodes.set
143   else:
144      print 'The Tor Exit nodes list is empty.'
145   s.close()