begining of socks5 proxy support. error handling is missing. see #799
This commit is contained in:
parent
0014e6e597
commit
9a6b090506
|
@ -17,6 +17,7 @@
|
|||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
<property name="urgency_hint">False</property>
|
||||
<signal name="destroy" handler="on_manage_proxies_window_destroy" last_modification_time="Wed, 08 Jun 2005 17:33:08 GMT"/>
|
||||
|
||||
<child>
|
||||
|
@ -209,7 +210,8 @@
|
|||
<child>
|
||||
<widget class="GtkComboBox" id="proxytype_combobox">
|
||||
<property name="visible">True</property>
|
||||
<property name="items" translatable="yes">HTTP Connect</property>
|
||||
<property name="items" translatable="yes">HTTP Connect
|
||||
SOCKS5</property>
|
||||
<property name="add_tearoffs">False</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="changed" handler="on_proxytype_combobox_changed" last_modification_time="Wed, 08 Jun 2005 17:45:26 GMT"/>
|
||||
|
|
|
@ -326,6 +326,7 @@ class Connection(ConnectionHandlers):
|
|||
proxy['port'] = gajim.config.get_per('proxies', p, 'port')
|
||||
proxy['user'] = gajim.config.get_per('proxies', p, 'user')
|
||||
proxy['password'] = gajim.config.get_per('proxies', p, 'pass')
|
||||
proxy['type'] = gajim.config.get_per('proxies', p, 'type')
|
||||
else:
|
||||
proxy = None
|
||||
|
||||
|
|
|
@ -88,6 +88,8 @@ class NBCommonClient(CommonClient):
|
|||
self.NonBlockingTLS.PlugOut()
|
||||
if self.__dict__.has_key('NBHTTPPROXYsocket'):
|
||||
self.NBHTTPPROXYsocket.PlugOut()
|
||||
if self.__dict__.has_key('NBSOCKS5PROXYsocket'):
|
||||
self.NBSOCKS5PROXYsocket.PlugOut()
|
||||
if self.__dict__.has_key('NonBlockingTcp'):
|
||||
self.NonBlockingTcp.PlugOut()
|
||||
|
||||
|
@ -102,9 +104,18 @@ class NBCommonClient(CommonClient):
|
|||
server = (self.Server, self.Port)
|
||||
self._Server, self._Proxy, self._Ssl = server , proxy, ssl
|
||||
self.on_stream_start = on_stream_start
|
||||
if proxy:
|
||||
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
|
||||
self._on_connected_failure, proxy, server)
|
||||
if proxy:
|
||||
if proxy.has_key('type'):
|
||||
type_ = proxy['type']
|
||||
if type_ == 'socks5':
|
||||
self.socket = transports_nb.NBSOCKS5PROXYsocket(self._on_connected,
|
||||
self._on_connected_failure, proxy, server)
|
||||
elif type_ == 'http':
|
||||
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
|
||||
self._on_connected_failure, proxy, server)
|
||||
else:
|
||||
self.socket = transports_nb.NBHTTPPROXYsocket(self._on_connected,
|
||||
self._on_connected_failure, proxy, server)
|
||||
else:
|
||||
self.connected = 'tcp'
|
||||
self.socket = transports_nb.NonBlockingTcp(self._on_connected,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
## GNU General Public License for more details.
|
||||
|
||||
import socket,select,base64,dispatcher_nb
|
||||
import struct
|
||||
from simplexml import ustr
|
||||
from client import PlugIn
|
||||
from idlequeue import IdleObject
|
||||
|
@ -885,6 +886,8 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
|||
self.DEBUG('Invalid proxy reply: %s %s %s' % (proto, code, desc),'error')
|
||||
self._owner.disconnected()
|
||||
return
|
||||
if len(reply) != 2:
|
||||
pass
|
||||
self.onreceive(self._on_proxy_auth)
|
||||
|
||||
def _on_proxy_auth(self, reply):
|
||||
|
@ -901,3 +904,152 @@ class NBHTTPPROXYsocket(NonBlockingTcp):
|
|||
def DEBUG(self, text, severity):
|
||||
''' Overwrites DEBUG tag to allow debug output be presented as "CONNECTproxy".'''
|
||||
return self._owner.DEBUG(DBG_CONNECT_PROXY, text, severity)
|
||||
|
||||
class NBSOCKS5PROXYsocket(NonBlockingTcp):
|
||||
'''SOCKS5 proxy connection class. Uses TCPsocket as the base class
|
||||
redefines only connect method. Allows to use SOCKS5 proxies with
|
||||
(optionally) simple authentication (only USERNAME/PASSWORD auth).
|
||||
'''
|
||||
def __init__(self, on_connect = None, on_connect_failure = None,
|
||||
proxy = None, server = None, use_srv = True):
|
||||
''' Caches proxy and target addresses.
|
||||
'proxy' argument is a dictionary with mandatory keys 'host' and 'port'
|
||||
(proxy address) and optional keys 'user' and 'password' to use for
|
||||
authentication. 'server' argument is a tuple of host and port -
|
||||
just like TCPsocket uses. '''
|
||||
self.on_connect_proxy = on_connect
|
||||
self.on_connect_failure = on_connect_failure
|
||||
NonBlockingTcp.__init__(self, self._on_tcp_connect, on_connect_failure,
|
||||
server, use_srv)
|
||||
self.DBG_LINE=DBG_CONNECT_PROXY
|
||||
self.server = server
|
||||
self.proxy = proxy
|
||||
self.ipaddr = None
|
||||
|
||||
def plugin(self, owner):
|
||||
''' Starts connection. Used interally. Returns non-empty string on
|
||||
success.'''
|
||||
owner.debug_flags.append(DBG_CONNECT_PROXY)
|
||||
NonBlockingTcp.plugin(self, owner)
|
||||
|
||||
def connect(self, dupe = None):
|
||||
''' Starts connection. Connects to proxy, supplies login and password to
|
||||
it (if were specified while creating instance). Instructs proxy to make
|
||||
connection to the target server. Returns non-empty sting on success.
|
||||
'''
|
||||
NonBlockingTcp.connect(self, (self.proxy['host'], self.proxy['port']))
|
||||
|
||||
def _on_tcp_connect(self):
|
||||
self.DEBUG('Proxy server contacted, performing authentification', 'start')
|
||||
if self.proxy.has_key('user') and self.proxy.has_key('password'):
|
||||
to_send = '\x05\x02\x00\x02'
|
||||
else:
|
||||
to_send = '\x05\x01\x00'
|
||||
self.onreceive(self._on_greeting_sent)
|
||||
self.send(to_send)
|
||||
|
||||
def _on_greeting_sent(self, reply):
|
||||
if reply is None:
|
||||
return
|
||||
if len(reply) != 2:
|
||||
raise error('Invalid proxy reply')
|
||||
if reply[0] != '\x05':
|
||||
self.DEBUG('Invalid proxy reply', 'error')
|
||||
self._owner.disconnected()
|
||||
return
|
||||
if reply[1] == '\x00':
|
||||
return self._on_proxy_auth('\x01\x00')
|
||||
elif reply[1] == '\x02':
|
||||
# TODO: Do authentification
|
||||
self.onreceive(self._on_proxy_auth)
|
||||
else:
|
||||
if reply[1] == '\xff':
|
||||
self.DEBUG('Authentification to proxy impossible: no acceptable '
|
||||
'auth method', 'error')
|
||||
else:
|
||||
self.DEBUG('Invalid proxy reply', 'error')
|
||||
self._owner.disconnected()
|
||||
return
|
||||
|
||||
def _on_proxy_auth(self, reply):
|
||||
if reply is None:
|
||||
return
|
||||
if len(reply) != 2:
|
||||
self.DEBUG('Invalid proxy reply', 'error')
|
||||
self._owner.disconnected()
|
||||
raise error('Invalid proxy reply')
|
||||
if reply[0] != '\x01':
|
||||
self.DEBUG('Invalid proxy reply', 'error')
|
||||
self._owner.disconnected()
|
||||
raise error('Invalid proxy reply')
|
||||
if reply[1] != '\x00':
|
||||
self.DEBUG('Authentification to proxy failed', 'error')
|
||||
self._owner.disconnected()
|
||||
return
|
||||
self.DEBUG('Authentification successfull. Jabber server contacted.','ok')
|
||||
# Request connection
|
||||
req = "\x05\x01\x00"
|
||||
# If the given destination address is an IP address, we'll
|
||||
# use the IPv4 address request even if remote resolving was specified.
|
||||
try:
|
||||
self.ipaddr = socket.inet_aton(self.server[0])
|
||||
req = req + "\x01" + ipaddr
|
||||
except socket.error:
|
||||
# Well it's not an IP number, so it's probably a DNS name.
|
||||
# if self.__proxy[3]==True:
|
||||
# Resolve remotely
|
||||
self.ipaddr = None
|
||||
req = req + "\x03" + chr(len(self.server[0])) + self.server[0]
|
||||
# else:
|
||||
# # Resolve locally
|
||||
# self.ipaddr = socket.inet_aton(socket.gethostbyname(self.server[0]))
|
||||
# req = req + "\x01" + ipaddr
|
||||
req = req + struct.pack(">H",self.server[1])
|
||||
self.onreceive(self._on_req_sent)
|
||||
self.send(req)
|
||||
|
||||
def _on_req_sent(self, reply):
|
||||
if reply is None:
|
||||
return
|
||||
if len(reply) < 10:
|
||||
self.DEBUG('Invalid proxy reply', 'error')
|
||||
self._owner.disconnected()
|
||||
raise error('Invalid proxy reply')
|
||||
if reply[0] != '\x05':
|
||||
self.DEBUG('Invalid proxy reply', 'error')
|
||||
self._owner.disconnected()
|
||||
raise error('Invalid proxy reply')
|
||||
if reply[1] != "\x00":
|
||||
# Connection failed
|
||||
self._owner.disconnected()
|
||||
if ord(reply[1])<9:
|
||||
errors = ['general SOCKS server failure',
|
||||
'connection not allowed by ruleset',
|
||||
'Network unreachable',
|
||||
'Host unreachable',
|
||||
'Connection refused',
|
||||
'TTL expired',
|
||||
'Command not supported',
|
||||
'Address type not supported'
|
||||
]
|
||||
txt = errors[ord(reply[1])-1]
|
||||
else:
|
||||
txt = 'Invalid proxy reply'
|
||||
self.DEBUG(txt, 'error')
|
||||
return
|
||||
# Get the bound address/port
|
||||
elif reply[3] == "\x01":
|
||||
begin, end = 3, 7
|
||||
elif reply[3] == "\x03":
|
||||
begin, end = 4, 4 + reply[4]
|
||||
else:
|
||||
self.DEBUG('Invalid proxy reply', 'error')
|
||||
self._owner.disconnected()
|
||||
return
|
||||
|
||||
if self.on_connect_proxy:
|
||||
self.on_connect_proxy()
|
||||
|
||||
def DEBUG(self, text, severity):
|
||||
''' Overwrites DEBUG tag to allow debug output be presented as "CONNECTproxy".'''
|
||||
return self._owner.DEBUG(DBG_CONNECT_PROXY, text, severity)
|
||||
|
|
|
@ -1655,6 +1655,7 @@ class ManageProxiesWindow:
|
|||
self.window.set_transient_for(gajim.interface.roster.window)
|
||||
self.proxies_treeview = self.xml.get_widget('proxies_treeview')
|
||||
self.proxyname_entry = self.xml.get_widget('proxyname_entry')
|
||||
self.proxytype_combobox = self.xml.get_widget('proxytype_combobox')
|
||||
self.init_list()
|
||||
self.xml.signal_autoconnect(self)
|
||||
self.window.show_all()
|
||||
|
@ -1670,7 +1671,7 @@ class ManageProxiesWindow:
|
|||
|
||||
def init_list(self):
|
||||
self.xml.get_widget('remove_proxy_button').set_sensitive(False)
|
||||
self.xml.get_widget('proxytype_combobox').set_sensitive(False)
|
||||
self.proxytype_combobox.set_sensitive(False)
|
||||
self.xml.get_widget('proxy_table').set_sensitive(False)
|
||||
model = gtk.ListStore(str)
|
||||
self.proxies_treeview.set_model(model)
|
||||
|
@ -1755,7 +1756,9 @@ class ManageProxiesWindow:
|
|||
'user'))
|
||||
proxypass_entry.set_text(gajim.config.get_per('proxies', proxy,
|
||||
'pass'))
|
||||
#FIXME: if we have several proxy types, set the combobox
|
||||
proxytype = gajim.config.get_per('proxies', proxy, 'type')
|
||||
types = ['http', 'socks5']
|
||||
self.proxytype_combobox.set_active(types.index(proxytype))
|
||||
if gajim.config.get_per('proxies', proxy, 'user'):
|
||||
useauth_checkbutton.set_active(True)
|
||||
|
||||
|
@ -1782,8 +1785,10 @@ class ManageProxiesWindow:
|
|||
model.set_value(iter, 0, new_name)
|
||||
|
||||
def on_proxytype_combobox_changed(self, widget):
|
||||
#FIXME: if we have several proxy types take them into account
|
||||
pass
|
||||
types = ['http', 'socks5']
|
||||
type_ = self.proxytype_combobox.get_active()
|
||||
proxy = self.proxyname_entry.get_text().decode('utf-8')
|
||||
gajim.config.set_per('proxies', proxy, 'type', types[type_])
|
||||
|
||||
def on_proxyhost_entry_changed(self, widget):
|
||||
value = widget.get_text().decode('utf-8')
|
||||
|
|
Loading…
Reference in New Issue