[tor-commits] [stem/master] Reconnecting socket after auth failures
atagar at torproject.org
atagar at torproject.org
Tue Dec 13 18:10:36 UTC 2011
commit 297a41b085a92eb1c5b5c92464d3bc9cd27cef94
Author: Damian Johnson <atagar at torproject.org>
Date: Tue Dec 13 10:06:53 2011 -0800
Reconnecting socket after auth failures
Tor disconnects the control socket after Failed AUTHENTICATE calls in an effort
to mitigate the issue discussed in...
http://archives.seul.org/or/announce/Sep-2007/msg00000.html
This is unintuitive to stem users so I'm making a best effort attempt to
reconnect the socket in those cases. This isn't guaranteed to succeed, but
checking is_alive() is far nicer for callers than a try/connect/except block.
---
stem/connection.py | 43 ++++++++++++++++++++-----------
test/integ/connection/authentication.py | 12 ++++++--
2 files changed, 37 insertions(+), 18 deletions(-)
diff --git a/stem/connection.py b/stem/connection.py
index 71b6e5b..e9bd5f7 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -126,8 +126,11 @@ def authenticate_none(control_socket, suppress_ctl_errors = True):
authenticate before they can be used, even if tor hasn't been configured to
use any authentication.
- For general usage use the authenticate function instead. If authentication
- fails then tor will close the control socket.
+ If authentication fails tor will disconnect and we'll make a best effort
+ attempt to re-establish the connection. This may not succeed, so check
+ is_alive() before using the socket further.
+
+ For general usage use the authenticate() function instead.
Arguments:
control_socket (stem.socket.ControlSocket) - socket to be authenticated
@@ -145,10 +148,13 @@ def authenticate_none(control_socket, suppress_ctl_errors = True):
# if we got anything but an OK response then error
if str(auth_response) != "OK":
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
+
raise OpenAuthRejected(str(auth_response), auth_response)
except stem.socket.ControllerError, exc:
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
if not suppress_ctl_errors: raise exc
else: raise OpenAuthRejected("Socket failed (%s)" % exc)
@@ -158,8 +164,11 @@ def authenticate_password(control_socket, password, suppress_ctl_errors = True):
Authenticates to a control socket that uses a password (via the
HashedControlPassword torrc option). Quotes in the password are escaped.
- For general usage use the authenticate function instead. If authentication
- fails then tor will close the control socket.
+ If authentication fails tor will disconnect and we'll make a best effort
+ attempt to re-establish the connection. This may not succeed, so check
+ is_alive() before using the socket further.
+
+ For general usage use the authenticate() function instead.
note: If you use this function directly, rather than authenticate(), we may
mistakenly raise a PasswordAuthRejected rather than IncorrectPassword. This
@@ -191,7 +200,8 @@ def authenticate_password(control_socket, password, suppress_ctl_errors = True):
# if we got anything but an OK response then error
if str(auth_response) != "OK":
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
# all we have to go on is the error message from tor...
# Password did not match HashedControlPassword value value from configuration...
@@ -202,7 +212,8 @@ def authenticate_password(control_socket, password, suppress_ctl_errors = True):
else:
raise PasswordAuthRejected(str(auth_response), auth_response)
except stem.socket.ControllerError, exc:
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
if not suppress_ctl_errors: raise exc
else: raise PasswordAuthRejected("Socket failed (%s)" % exc)
@@ -217,8 +228,11 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
The IncorrectCookieSize and UnreadableCookieFile exceptions take precidence
over the other types.
- For general usage use the authenticate function instead. If authentication
- fails then tor will close the control socket.
+ If authentication fails tor will disconnect and we'll make a best effort
+ attempt to re-establish the connection. This may not succeed, so check
+ is_alive() before using the socket further.
+
+ For general usage use the authenticate() function instead.
note: If you use this function directly, rather than authenticate(), we may
mistakenly raise a CookieAuthRejected rather than IncorrectCookieValue. This
@@ -241,7 +255,6 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
"""
if not os.path.exists(cookie_path):
- control_socket.close()
raise UnreadableCookieFile("Authentication failed: '%s' doesn't exist" % cookie_path)
# Abort if the file isn't 32 bytes long. This is to avoid exposing arbitrary
@@ -256,7 +269,6 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
auth_cookie_size = os.path.getsize(cookie_path)
if auth_cookie_size != 32:
- control_socket.close()
exc_msg = "Authentication failed: authentication cookie '%s' is the wrong size (%i bytes instead of 32)" % (cookie_path, auth_cookie_size)
raise IncorrectCookieSize(exc_msg)
@@ -265,7 +277,6 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
auth_cookie_contents = auth_cookie_file.read()
auth_cookie_file.close()
except IOError, exc:
- control_socket.close()
raise UnreadableCookieFile("Authentication failed: unable to read '%s' (%s)" % (cookie_path, exc))
try:
@@ -274,7 +285,8 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
# if we got anything but an OK response then error
if str(auth_response) != "OK":
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
# all we have to go on is the error message from tor...
# ... Authentication cookie did not match expected value.
@@ -286,7 +298,8 @@ def authenticate_cookie(control_socket, cookie_path, suppress_ctl_errors = True)
else:
raise CookieAuthRejected(str(auth_response), auth_response)
except stem.socket.ControllerError, exc:
- control_socket.close()
+ try: control_socket.connect()
+ except: pass
if not suppress_ctl_errors: raise exc
else: raise CookieAuthRejected("Socket failed (%s)" % exc)
diff --git a/test/integ/connection/authentication.py b/test/integ/connection/authentication.py
index ee36946..3d7d199 100644
--- a/test/integ/connection/authentication.py
+++ b/test/integ/connection/authentication.py
@@ -246,8 +246,9 @@ class TestAuthenticate(unittest.TestCase):
control_socket.close()
self.fail()
except stem.connection.AuthenticationFailure, exc:
- self.assertFalse(control_socket.is_alive())
+ self.assertTrue(control_socket.is_alive())
self.assertEqual(failure_msg, str(exc))
+ control_socket.close()
def _check_auth(self, auth_type, *auth_args):
"""
@@ -268,8 +269,13 @@ class TestAuthenticate(unittest.TestCase):
control_socket = runner.get_tor_socket(False)
auth_function = self._get_auth_function(control_socket, auth_type, *auth_args)
- # run the authentication, letting this raise if there's a problem
- auth_function()
+ # run the authentication, re-raising if there's a problem
+ try:
+ auth_function()
+ except stem.connection.AuthenticationFailure, exc:
+ self.assertTrue(control_socket.is_alive())
+ control_socket.close()
+ raise exc
# issues a 'GETINFO config-file' query to confirm that we can use the socket
control_socket.send("GETINFO config-file")
More information about the tor-commits
mailing list