handle proxy errors. fixes #799 (socks5 proxies should now be supported. tests needed)
This commit is contained in:
parent
56bcc2e1fa
commit
cba44a43a1
|
@ -368,6 +368,15 @@ class Connection(ConnectionHandlers):
|
||||||
self._hosts = [i for i in result_array]
|
self._hosts = [i for i in result_array]
|
||||||
self.connect_to_next_host()
|
self.connect_to_next_host()
|
||||||
|
|
||||||
|
def on_proxy_failure(self, reason):
|
||||||
|
log.debug('Connection to proxy failed')
|
||||||
|
self.time_to_reconnect = None
|
||||||
|
self.on_connect_failure = None
|
||||||
|
self.disconnect(on_purpose = True)
|
||||||
|
self.dispatch('STATUS', 'offline')
|
||||||
|
self.dispatch('CONNECTION_LOST',
|
||||||
|
(_('Connection to proxy failed'), reason))
|
||||||
|
|
||||||
def connect_to_next_host(self, retry = False):
|
def connect_to_next_host(self, retry = False):
|
||||||
if len(self._hosts):
|
if len(self._hosts):
|
||||||
if self.last_connection:
|
if self.last_connection:
|
||||||
|
@ -377,10 +386,12 @@ class Connection(ConnectionHandlers):
|
||||||
if gajim.verbose:
|
if gajim.verbose:
|
||||||
con = common.xmpp.NonBlockingClient(self._hostname, caller = self,
|
con = common.xmpp.NonBlockingClient(self._hostname, caller = self,
|
||||||
on_connect = self.on_connect_success,
|
on_connect = self.on_connect_success,
|
||||||
|
on_proxy_failure = self.on_proxy_failure,
|
||||||
on_connect_failure = self.connect_to_next_host)
|
on_connect_failure = self.connect_to_next_host)
|
||||||
else:
|
else:
|
||||||
con = common.xmpp.NonBlockingClient(self._hostname, debug = [], caller = self,
|
con = common.xmpp.NonBlockingClient(self._hostname, debug = [], caller = self,
|
||||||
on_connect = self.on_connect_success,
|
on_connect = self.on_connect_success,
|
||||||
|
on_proxy_failure = self.on_proxy_failure,
|
||||||
on_connect_failure = self.connect_to_next_host)
|
on_connect_failure = self.connect_to_next_host)
|
||||||
self.last_connection = con
|
self.last_connection = con
|
||||||
# increase default timeout for server responses
|
# increase default timeout for server responses
|
||||||
|
@ -397,7 +408,6 @@ class Connection(ConnectionHandlers):
|
||||||
log.info("Connecting to %s: [%s:%d]", self.name, host['host'], host['port'])
|
log.info("Connecting to %s: [%s:%d]", self.name, host['host'], host['port'])
|
||||||
con.connect((host['host'], host['port']), proxy = self._proxy,
|
con.connect((host['host'], host['port']), proxy = self._proxy,
|
||||||
secure = self._secure)
|
secure = self._secure)
|
||||||
return
|
|
||||||
else:
|
else:
|
||||||
if not retry and self.retrycount == 0:
|
if not retry and self.retrycount == 0:
|
||||||
log.debug("Out of hosts, giving up connecting to %s", self.name)
|
log.debug("Out of hosts, giving up connecting to %s", self.name)
|
||||||
|
|
|
@ -32,7 +32,7 @@ from client import *
|
||||||
class NBCommonClient(CommonClient):
|
class NBCommonClient(CommonClient):
|
||||||
''' Base for Client and Component classes.'''
|
''' Base for Client and Component classes.'''
|
||||||
def __init__(self, server, port=5222, debug=['always', 'nodebuilder'], caller=None,
|
def __init__(self, server, port=5222, debug=['always', 'nodebuilder'], caller=None,
|
||||||
on_connect=None, on_connect_failure=None):
|
on_connect=None, on_proxy_failure=None, on_connect_failure=None):
|
||||||
''' Caches server name and (optionally) port to connect to. "debug" parameter specifies
|
''' Caches server name and (optionally) port to connect to. "debug" parameter specifies
|
||||||
the debug IDs that will go into debug output. You can either specifiy an "include"
|
the debug IDs that will go into debug output. You can either specifiy an "include"
|
||||||
or "exclude" list. The latter is done via adding "always" pseudo-ID to the list.
|
or "exclude" list. The latter is done via adding "always" pseudo-ID to the list.
|
||||||
|
@ -65,6 +65,7 @@ class NBCommonClient(CommonClient):
|
||||||
self.idlequeue = None
|
self.idlequeue = None
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self.on_connect = on_connect
|
self.on_connect = on_connect
|
||||||
|
self.on_proxy_failure = on_proxy_failure
|
||||||
self.on_connect_failure = on_connect_failure
|
self.on_connect_failure = on_connect_failure
|
||||||
|
|
||||||
def set_idlequeue(self, idlequeue):
|
def set_idlequeue(self, idlequeue):
|
||||||
|
@ -108,14 +109,17 @@ class NBCommonClient(CommonClient):
|
||||||
if proxy.has_key('type'):
|
if proxy.has_key('type'):
|
||||||
type_ = proxy['type']
|
type_ = proxy['type']
|
||||||
if type_ == 'socks5':
|
if type_ == 'socks5':
|
||||||
self.socket = transports_nb.NBSOCKS5PROXYsocket(self._on_connected,
|
self.socket = transports_nb.NBSOCKS5PROXYsocket(
|
||||||
|
self._on_connected, self._on_proxy_failure,
|
||||||
self._on_connected_failure, proxy, server)
|
self._on_connected_failure, proxy, server)
|
||||||
elif type_ == 'http':
|
elif type_ == 'http':
|
||||||
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
|
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
|
||||||
self._on_connected_failure, proxy, server)
|
self._on_proxy_failure, self._on_connected_failure, proxy,
|
||||||
|
server)
|
||||||
else:
|
else:
|
||||||
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
|
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
|
||||||
self._on_connected_failure, proxy, server)
|
self._on_proxy_failure, self._on_connected_failure, proxy,
|
||||||
|
server)
|
||||||
else:
|
else:
|
||||||
self.connected = 'tcp'
|
self.connected = 'tcp'
|
||||||
self.socket = transports_nb.NonBlockingTcp(self._on_connected,
|
self.socket = transports_nb.NonBlockingTcp(self._on_connected,
|
||||||
|
@ -127,6 +131,10 @@ class NBCommonClient(CommonClient):
|
||||||
self.on_stream_start = on_stream_start
|
self.on_stream_start = on_stream_start
|
||||||
self.onreceive(self._on_receive_document_attrs)
|
self.onreceive(self._on_receive_document_attrs)
|
||||||
|
|
||||||
|
def _on_proxy_failure(self, reason):
|
||||||
|
if self.on_proxy_failure:
|
||||||
|
self.on_proxy_failure(reason)
|
||||||
|
|
||||||
def _on_connected_failure(self, retry = None):
|
def _on_connected_failure(self, retry = None):
|
||||||
if self.socket:
|
if self.socket:
|
||||||
self.socket.disconnect()
|
self.socket.disconnect()
|
||||||
|
|
|
@ -374,7 +374,10 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
||||||
self.state = -2
|
self.state = -2
|
||||||
self.sendqueue = None
|
self.sendqueue = None
|
||||||
self.remove_timeout()
|
self.remove_timeout()
|
||||||
self._owner.disconnected()
|
try:
|
||||||
|
self._owner.disconnected()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
self.idlequeue.unplug_idle(self.fd)
|
self.idlequeue.unplug_idle(self.fd)
|
||||||
sock = getattr(self, '_sock', None)
|
sock = getattr(self, '_sock', None)
|
||||||
if sock:
|
if sock:
|
||||||
|
@ -609,7 +612,10 @@ class NonBlockingTcp(PlugIn, IdleObject):
|
||||||
def getName(self):
|
def getName(self):
|
||||||
''' Return the server's name, or 'getHost()' if not available.'''
|
''' Return the server's name, or 'getHost()' if not available.'''
|
||||||
retval = None
|
retval = None
|
||||||
retval = gattr(self._owner, 'name')
|
try:
|
||||||
|
retval = gattr(self._owner, 'name')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
if retval: return retval
|
if retval: return retval
|
||||||
return self.getHost()
|
return self.getHost()
|
||||||
|
|
||||||
|
@ -834,12 +840,13 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
||||||
(optionally) simple authentication (using login and password).
|
(optionally) simple authentication (using login and password).
|
||||||
|
|
||||||
'''
|
'''
|
||||||
def __init__(self, on_connect =None, on_connect_failure = None,proxy = None,server = None,use_srv=True):
|
def __init__(self, on_connect =None, on_proxy_failure=None, on_connect_failure = None,proxy = None,server = None,use_srv=True):
|
||||||
''' Caches proxy and target addresses.
|
''' Caches proxy and target addresses.
|
||||||
'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address)
|
'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address)
|
||||||
and optional keys 'user' and 'password' to use for authentication.
|
and optional keys 'user' and 'password' to use for authentication.
|
||||||
'server' argument is a tuple of host and port - just like TCPsocket uses. '''
|
'server' argument is a tuple of host and port - just like TCPsocket uses. '''
|
||||||
self.on_connect_proxy = on_connect
|
self.on_connect_proxy = on_connect
|
||||||
|
self.on_proxy_failure = on_proxy_failure
|
||||||
self.on_connect_failure = on_connect_failure
|
self.on_connect_failure = on_connect_failure
|
||||||
NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure, server, use_srv)
|
NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure, server, use_srv)
|
||||||
self.DBG_LINE=DBG_CONNECT_PROXY
|
self.DBG_LINE=DBG_CONNECT_PROXY
|
||||||
|
@ -881,10 +888,12 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
||||||
except:
|
except:
|
||||||
log.error("_on_headers_sent:", exc_info=True)
|
log.error("_on_headers_sent:", exc_info=True)
|
||||||
#traceback.print_exc()
|
#traceback.print_exc()
|
||||||
raise error('Invalid proxy reply')
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
|
return
|
||||||
if code <> '200':
|
if code <> '200':
|
||||||
self.DEBUG('Invalid proxy reply: %s %s %s' % (proto, code, desc),'error')
|
self.DEBUG('Invalid proxy reply: %s %s %s' % (proto, code, desc),'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
return
|
return
|
||||||
if len(reply) != 2:
|
if len(reply) != 2:
|
||||||
pass
|
pass
|
||||||
|
@ -893,9 +902,11 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
||||||
def _on_proxy_auth(self, reply):
|
def _on_proxy_auth(self, reply):
|
||||||
if self.reply.find('\n\n') == -1:
|
if self.reply.find('\n\n') == -1:
|
||||||
if reply is None:
|
if reply is None:
|
||||||
|
self.on_proxy_failure('Proxy authentification failed')
|
||||||
return
|
return
|
||||||
if reply.find('\n\n') == -1:
|
if reply.find('\n\n') == -1:
|
||||||
self.reply += reply.replace('\r', '')
|
self.reply += reply.replace('\r', '')
|
||||||
|
self.on_proxy_failure('Proxy authentification failed')
|
||||||
return
|
return
|
||||||
self.DEBUG('Authentification successfull. Jabber server contacted.','ok')
|
self.DEBUG('Authentification successfull. Jabber server contacted.','ok')
|
||||||
if self.on_connect_proxy:
|
if self.on_connect_proxy:
|
||||||
|
@ -910,14 +921,15 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||||
redefines only connect method. Allows to use SOCKS5 proxies with
|
redefines only connect method. Allows to use SOCKS5 proxies with
|
||||||
(optionally) simple authentication (only USERNAME/PASSWORD auth).
|
(optionally) simple authentication (only USERNAME/PASSWORD auth).
|
||||||
'''
|
'''
|
||||||
def __init__(self, on_connect = None, on_connect_failure = None,
|
def __init__(self, on_connect = None, on_proxy_failure = None,
|
||||||
proxy = None, server = None, use_srv = True):
|
on_connect_failure = None, proxy = None, server = None, use_srv = True):
|
||||||
''' Caches proxy and target addresses.
|
''' Caches proxy and target addresses.
|
||||||
'proxy' argument is a dictionary with mandatory keys 'host' and 'port'
|
'proxy' argument is a dictionary with mandatory keys 'host' and 'port'
|
||||||
(proxy address) and optional keys 'user' and 'password' to use for
|
(proxy address) and optional keys 'user' and 'password' to use for
|
||||||
authentication. 'server' argument is a tuple of host and port -
|
authentication. 'server' argument is a tuple of host and port -
|
||||||
just like TCPsocket uses. '''
|
just like TCPsocket uses. '''
|
||||||
self.on_connect_proxy = on_connect
|
self.on_connect_proxy = on_connect
|
||||||
|
self.on_proxy_failure = on_proxy_failure
|
||||||
self.on_connect_failure = on_connect_failure
|
self.on_connect_failure = on_connect_failure
|
||||||
NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure,
|
NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure,
|
||||||
server, use_srv)
|
server, use_srv)
|
||||||
|
@ -952,23 +964,31 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||||
if reply is None:
|
if reply is None:
|
||||||
return
|
return
|
||||||
if len(reply) != 2:
|
if len(reply) != 2:
|
||||||
raise error('Invalid proxy reply')
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
|
return
|
||||||
if reply[0] != '\x05':
|
if reply[0] != '\x05':
|
||||||
self.DEBUG('Invalid proxy reply', 'error')
|
self.DEBUG('Invalid proxy reply', 'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
return
|
return
|
||||||
if reply[1] == '\x00':
|
if reply[1] == '\x00':
|
||||||
return self._on_proxy_auth('\x01\x00')
|
return self._on_proxy_auth('\x01\x00')
|
||||||
elif reply[1] == '\x02':
|
elif reply[1] == '\x02':
|
||||||
# TODO: Do authentification
|
to_send = '\x01' + chr(len(self.proxy['user'])) + self.proxy['user'] +\
|
||||||
|
chr(len(self.proxy['password'])) + self.proxy['password']
|
||||||
self.onreceive(self._on_proxy_auth)
|
self.onreceive(self._on_proxy_auth)
|
||||||
|
self.send(to_send)
|
||||||
else:
|
else:
|
||||||
if reply[1] == '\xff':
|
if reply[1] == '\xff':
|
||||||
self.DEBUG('Authentification to proxy impossible: no acceptable '
|
self.DEBUG('Authentification to proxy impossible: no acceptable '
|
||||||
'auth method', 'error')
|
'auth method', 'error')
|
||||||
else:
|
self._owner.disconnected()
|
||||||
self.DEBUG('Invalid proxy reply', 'error')
|
self.on_proxy_failure('Authentification to proxy impossible: no '
|
||||||
|
'acceptable authentification method')
|
||||||
|
return
|
||||||
|
self.DEBUG('Invalid proxy reply', 'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
return
|
return
|
||||||
|
|
||||||
def _on_proxy_auth(self, reply):
|
def _on_proxy_auth(self, reply):
|
||||||
|
@ -977,14 +997,17 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||||
if len(reply) != 2:
|
if len(reply) != 2:
|
||||||
self.DEBUG('Invalid proxy reply', 'error')
|
self.DEBUG('Invalid proxy reply', 'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
raise error('Invalid proxy reply')
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
|
return
|
||||||
if reply[0] != '\x01':
|
if reply[0] != '\x01':
|
||||||
self.DEBUG('Invalid proxy reply', 'error')
|
self.DEBUG('Invalid proxy reply', 'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
raise error('Invalid proxy reply')
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
|
return
|
||||||
if reply[1] != '\x00':
|
if reply[1] != '\x00':
|
||||||
self.DEBUG('Authentification to proxy failed', 'error')
|
self.DEBUG('Authentification to proxy failed', 'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
|
self.on_proxy_failure('Authentification to proxy failed')
|
||||||
return
|
return
|
||||||
self.DEBUG('Authentification successfull. Jabber server contacted.','ok')
|
self.DEBUG('Authentification successfull. Jabber server contacted.','ok')
|
||||||
# Request connection
|
# Request connection
|
||||||
|
@ -1014,11 +1037,13 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||||
if len(reply) < 10:
|
if len(reply) < 10:
|
||||||
self.DEBUG('Invalid proxy reply', 'error')
|
self.DEBUG('Invalid proxy reply', 'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
raise error('Invalid proxy reply')
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
|
return
|
||||||
if reply[0] != '\x05':
|
if reply[0] != '\x05':
|
||||||
self.DEBUG('Invalid proxy reply', 'error')
|
self.DEBUG('Invalid proxy reply', 'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
raise error('Invalid proxy reply')
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
|
return
|
||||||
if reply[1] != "\x00":
|
if reply[1] != "\x00":
|
||||||
# Connection failed
|
# Connection failed
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
|
@ -1036,6 +1061,7 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||||
else:
|
else:
|
||||||
txt = 'Invalid proxy reply'
|
txt = 'Invalid proxy reply'
|
||||||
self.DEBUG(txt, 'error')
|
self.DEBUG(txt, 'error')
|
||||||
|
self.on_proxy_failure(txt)
|
||||||
return
|
return
|
||||||
# Get the bound address/port
|
# Get the bound address/port
|
||||||
elif reply[3] == "\x01":
|
elif reply[3] == "\x01":
|
||||||
|
@ -1045,6 +1071,7 @@ class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||||
else:
|
else:
|
||||||
self.DEBUG('Invalid proxy reply', 'error')
|
self.DEBUG('Invalid proxy reply', 'error')
|
||||||
self._owner.disconnected()
|
self._owner.disconnected()
|
||||||
|
self.on_proxy_failure('Invalid proxy reply')
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.on_connect_proxy:
|
if self.on_connect_proxy:
|
||||||
|
|
Loading…
Reference in New Issue