Merge remote-tracking branch 'tor-gitlab/mr/513' into main
[tor.git] / src / test / test_rebind.py
blob6b72ece91117b79d40177b0cd57e51f945ee99ab
1 # Future imports for Python 2.7, mandatory in 3.0
2 from __future__ import division
3 from __future__ import print_function
4 from __future__ import unicode_literals
6 import errno
7 import logging
8 import os
9 import random
10 import socket
11 import subprocess
12 import sys
13 import time
15 LOG_TIMEOUT = 60.0
16 LOG_WAIT = 0.1
18 def fail(msg):
19 logging.error('FAIL')
20 sys.exit(msg)
22 def skip(msg):
23 logging.warning('SKIP: {}'.format(msg))
24 sys.exit(77)
26 def try_connecting_to_socksport():
27 socks_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
28 e = socks_socket.connect_ex(('127.0.0.1', socks_port))
29 if e:
30 tor_process.terminate()
31 fail('Cannot connect to SOCKSPort: error ' + os.strerror(e))
32 socks_socket.close()
34 def wait_for_log(s):
35 cutoff = time.time() + LOG_TIMEOUT
36 while time.time() < cutoff:
37 l = tor_process.stdout.readline()
38 l = l.decode('utf8', 'backslashreplace')
39 if s in l:
40 logging.info('Tor logged: "{}"'.format(l.strip()))
41 return
42 # readline() returns a blank string when there is no output
43 # avoid busy-waiting
44 if len(l) == 0:
45 logging.debug('Tor has not logged anything, waiting for "{}"'.format(s))
46 time.sleep(LOG_WAIT)
47 else:
48 logging.info('Tor logged: "{}", waiting for "{}"'.format(l.strip(), s))
49 fail('Could not find "{}" in logs after {} seconds'.format(s, LOG_TIMEOUT))
51 def pick_random_port():
52 port = 0
53 random.seed()
55 for i in range(8):
56 port = random.randint(10000, 60000)
57 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
58 if s.connect_ex(('127.0.0.1', port)) == 0:
59 s.close()
60 else:
61 break
63 if port == 0:
64 fail('Could not find a random free port between 10000 and 60000')
66 return port
68 logging.basicConfig(level=logging.DEBUG,
69 format='%(asctime)s.%(msecs)03d %(message)s',
70 datefmt='%Y-%m-%d %H:%M:%S')
72 if sys.hexversion < 0x02070000:
73 fail("ERROR: unsupported Python version (should be >= 2.7)")
75 if sys.hexversion > 0x03000000 and sys.hexversion < 0x03010000:
76 fail("ERROR: unsupported Python3 version (should be >= 3.1)")
78 if 'TOR_SKIP_TEST_REBIND' in os.environ:
79 skip('$TOR_SKIP_TEST_REBIND is set')
81 control_port = pick_random_port()
82 socks_port = pick_random_port()
84 assert control_port != 0
85 assert socks_port != 0
87 if len(sys.argv) < 3:
88 fail('Usage: %s <path-to-tor> <data-dir>' % sys.argv[0])
90 if not os.path.exists(sys.argv[1]):
91 fail('ERROR: cannot find tor at %s' % sys.argv[1])
92 if not os.path.exists(sys.argv[2]):
93 fail('ERROR: cannot find datadir at %s' % sys.argv[2])
95 tor_path = sys.argv[1]
96 data_dir = sys.argv[2]
98 empty_torrc_path = os.path.join(data_dir, 'empty_torrc')
99 open(empty_torrc_path, 'w').close()
100 empty_defaults_torrc_path = os.path.join(data_dir, 'empty_defaults_torrc')
101 open(empty_defaults_torrc_path, 'w').close()
103 tor_process = subprocess.Popen([tor_path,
104 '-DataDirectory', data_dir,
105 '-ControlPort', '127.0.0.1:{}'.format(control_port),
106 '-SOCKSPort', '127.0.0.1:{}'.format(socks_port),
107 '-Log', 'debug stdout',
108 '-LogTimeGranularity', '1',
109 '-FetchServerDescriptors', '0',
110 '-f', empty_torrc_path,
111 '--defaults-torrc', empty_defaults_torrc_path,
113 stdout=subprocess.PIPE,
114 stderr=subprocess.PIPE)
116 if tor_process == None:
117 fail('ERROR: running tor failed')
119 wait_for_log('Opened Control listener')
121 try_connecting_to_socksport()
123 control_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
124 if control_socket.connect_ex(('127.0.0.1', control_port)):
125 tor_process.terminate()
126 fail('Cannot connect to ControlPort')
128 control_socket.sendall('AUTHENTICATE \r\n'.encode('ascii'))
129 control_socket.sendall('SETCONF SOCKSPort=0.0.0.0:{}\r\n'.format(socks_port).encode('ascii'))
130 wait_for_log('Opened Socks listener')
132 try_connecting_to_socksport()
134 control_socket.sendall('SETCONF SOCKSPort=127.0.0.1:{}\r\n'.format(socks_port).encode('ascii'))
135 wait_for_log('Opened Socks listener')
137 try_connecting_to_socksport()
139 control_socket.sendall('SIGNAL HALT\r\n'.encode('ascii'))
141 wait_for_log('exiting cleanly')
142 logging.info('OK')
144 try:
145 tor_process.terminate()
146 except OSError as e:
147 if e.errno == errno.ESRCH: # errno 3: No such process
148 # assume tor has already exited due to SIGNAL HALT
149 logging.warn("Tor has already exited")
150 else:
151 raise