- use transport sid to compute hash sent to proxies

- Don't use XTLS when using proxies
This commit is contained in:
Yann Leboulanger 2010-08-25 12:05:14 +02:00
parent 556236ac38
commit 833983eab8
5 changed files with 70 additions and 44 deletions

View File

@ -141,26 +141,26 @@ class ConnectionJingle(object):
def start_file_transfer(self, jid, file_props): def start_file_transfer(self, jid, file_props):
logger.info("start file transfer with file: %s" % file_props) logger.info("start file transfer with file: %s" % file_props)
jingle = self.get_jingle_session(jid, media='file') jingle = self.get_jingle_session(jid, media='file')
contact = gajim.contacts.get_contact_with_highest_priority(self.name, contact = gajim.contacts.get_contact_with_highest_priority(self.name,
gajim.get_jid_without_resource(jid)) gajim.get_jid_without_resource(jid))
if contact is None: if contact is None:
return return
use_security = contact.supports(xmpp.NS_JINGLE_XTLS) use_security = contact.supports(xmpp.NS_JINGLE_XTLS)
if jingle: if jingle:
file_props['sid'] = jingle.sid file_props['sid'] = jingle.sid
jingle.add_content('file', c = JingleFileTransfer(jingle, file_props=file_props,
JingleFileTransfer(jingle, file_props = file_props, use_security=use_security) use_security=use_security)
) jingle.add_content('file', c)
else: else:
jingle = JingleSession(self, weinitiate=True, jid=jid) jingle = JingleSession(self, weinitiate=True, jid=jid)
self.__sessions[jingle.sid] = jingle self.__sessions[jingle.sid] = jingle
file_props['sid'] = jingle.sid file_props['sid'] = jingle.sid
jingle.add_content('file', c = JingleFileTransfer(jingle, file_props=file_props,
JingleFileTransfer(jingle, file_props=file_props, use_security=use_security) use_security=use_security)
) jingle.add_content('file', c)
jingle.start_session() jingle.start_session()
return jingle.sid return c.transport.sid
def iter_jingle_sessions(self, jid, sid=None, media=None): def iter_jingle_sessions(self, jid, sid=None, media=None):
if sid: if sid:

View File

@ -67,18 +67,21 @@ class JingleFileTransfer(JingleContent):
self.file_props['sender'] = session.ourjid self.file_props['sender'] = session.ourjid
self.file_props['receiver'] = session.peerjid self.file_props['receiver'] = session.peerjid
self.file_props['session-type'] = 'jingle' self.file_props['session-type'] = 'jingle'
self.file_props['sid'] = session.sid self.file_props['session-sid'] = session.sid
self.file_props['transfered_size'] = [] self.file_props['transfered_size'] = []
log.info("FT request: %s" % file_props) log.info("FT request: %s" % file_props)
if transport is None: if transport is None:
self.transport = JingleTransportSocks5() self.transport = JingleTransportSocks5()
self.transport.set_connection(session.connection)
self.transport.set_file_props(self.file_props) self.transport.set_file_props(self.file_props)
self.transport.set_our_jid(session.ourjid) self.transport.set_our_jid(session.ourjid)
self.transport.set_connection(session.connection)
log.info('ourjid: %s' % session.ourjid) log.info('ourjid: %s' % session.ourjid)
if self.file_props is not None:
self.file_props['sid'] = self.transport.sid
self.session = session self.session = session
self.media = 'file' self.media = 'file'
@ -109,17 +112,19 @@ class JingleFileTransfer(JingleContent):
file_props['receiver'] = self.session.ourjid file_props['receiver'] = self.session.ourjid
log.info("ourjid: %s" % self.session.ourjid) log.info("ourjid: %s" % self.session.ourjid)
file_props['sid'] = unicode(stanza.getTag('jingle').getAttr('sid')) file_props['session-sid'] = unicode(stanza.getTag('jingle').getAttr('sid'))
file_props['transfered_size'] = [] file_props['transfered_size'] = []
self.file_props = file_props self.file_props = file_props
self.session.connection.files_props[file_props['sid']] = file_props
if self.transport is None: if self.transport is None:
self.transport = JingleTransportSocks5() self.transport = JingleTransportSocks5()
self.transport.set_our_jid(self.session.ourjid) self.transport.set_our_jid(self.session.ourjid)
self.transport.set_connection(self.session.connection) self.transport.set_connection(self.session.connection)
self.file_props['sid'] = self.transport.sid
self.session.connection.files_props[file_props['sid']] = file_props
self.transport.set_file_props(self.file_props) self.transport.set_file_props(self.file_props)
if self.file_props.has_key("streamhosts"): if self.file_props.has_key('streamhosts'):
self.file_props['streamhosts'].extend( self.file_props['streamhosts'].extend(
self.transport.remote_candidates) self.transport.remote_candidates)
else: else:
@ -247,7 +252,8 @@ class JingleFileTransfer(JingleContent):
content.setAttr('name', 'file') content.setAttr('name', 'file')
transport = xmpp.Node('transport') transport = xmpp.Node('transport')
transport.setAttr('xmlns', xmpp.NS_JINGLE_BYTESTREAM) transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM)
transport.setAttr('sid', self.transport.sid)
candidateused = xmpp.Node('candidate-used') candidateused = xmpp.Node('candidate-used')
candidateused.setAttr('cid', streamhost['cid']) candidateused.setAttr('cid', streamhost['cid'])

View File

@ -17,6 +17,7 @@ Handles Jingle Transports (currently only ICE-UDP)
import xmpp import xmpp
import socket import socket
from common import helpers
from common import gajim from common import gajim
from common.protocol.bytestream import ConnectionSocks5Bytestream from common.protocol.bytestream import ConnectionSocks5Bytestream
import logging import logging
@ -29,7 +30,7 @@ transports = {}
def get_jingle_transport(node): def get_jingle_transport(node):
namespace = node.getNamespace() namespace = node.getNamespace()
if namespace in transports: if namespace in transports:
return transports[namespace]() return transports[namespace](node)
class TransportType(object): class TransportType(object):
@ -83,10 +84,13 @@ class JingleTransportSocks5(JingleTransport):
Socks5 transport in jingle scenario Socks5 transport in jingle scenario
Note: Don't forget to call set_file_props after initialization Note: Don't forget to call set_file_props after initialization
""" """
def __init__(self): def __init__(self, node=None):
JingleTransport.__init__(self, TransportType.streaming) JingleTransport.__init__(self, TransportType.streaming)
self.connection = None self.connection = None
self.remote_candidates = [] self.remote_candidates = []
self.sid = None
if node and node.getAttr('sid'):
self.sid = node.getAttr('sid')
def set_file_props(self, file_props): def set_file_props(self, file_props):
self.file_props = file_props self.file_props = file_props
@ -96,7 +100,9 @@ class JingleTransportSocks5(JingleTransport):
def set_connection(self, conn): def set_connection(self, conn):
self.connection = conn self.connection = conn
if not self.sid:
self.sid = self.connection.connection.getAnID()
def make_candidate(self, candidate): def make_candidate(self, candidate):
import logging import logging
log = logging.getLogger() log = logging.getLogger()
@ -118,26 +124,32 @@ class JingleTransportSocks5(JingleTransport):
self._add_proxy_candidates() self._add_proxy_candidates()
transport = JingleTransport.make_transport(self, candidates) transport = JingleTransport.make_transport(self, candidates)
transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM) transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM)
transport.setAttr('sid', self.sid)
return transport return transport
def parse_transport_stanza(self, transport): def parse_transport_stanza(self, transport):
candidates = [] candidates = []
for candidate in transport.iterTags('candidate'): for candidate in transport.iterTags('candidate'):
typ = 'direct' # default value
if candidate.has_attr('type'):
typ = candidate['type']
cand = { cand = {
'state': 0, 'state': 0,
'target': self.ourjid, 'target': self.ourjid,
'host': candidate['host'], 'host': candidate['host'],
'port': candidate['port'], 'port': candidate['port'],
'cid': candidate['cid'] 'cid': candidate['cid'],
'type': typ
} }
candidates.append(cand) candidates.append(cand)
# we need this when we construct file_props on session-initiation # we need this when we construct file_props on session-initiation
self.remote_candidates = candidates self.remote_candidates = candidates
return candidates return candidates
def _add_local_ips_as_candidates(self): def _add_local_ips_as_candidates(self):
return
if not self.connection: if not self.connection:
return return
local_ip_cand = [] local_ip_cand = []
@ -149,9 +161,9 @@ class JingleTransportSocks5(JingleTransport):
c['type'] = 'direct' c['type'] = 'direct'
c['jid'] = self.ourjid c['jid'] = self.ourjid
c['priority'] = (2**16) * type_preference c['priority'] = (2**16) * type_preference
local_ip_cand.append(c) local_ip_cand.append(c)
for addr in socket.getaddrinfo(socket.gethostname(), None): for addr in socket.getaddrinfo(socket.gethostname(), None):
if not addr[4][0] in local_ip_cand and not addr[4][0].startswith('127'): if not addr[4][0] in local_ip_cand and not addr[4][0].startswith('127'):
c = {'host': addr[4][0]} c = {'host': addr[4][0]}
@ -167,13 +179,14 @@ class JingleTransportSocks5(JingleTransport):
self.candidates += local_ip_cand self.candidates += local_ip_cand
def _add_additional_candidates(self): def _add_additional_candidates(self):
return
if not self.connection: if not self.connection:
return return
type_preference = 126 type_preference = 126
additional_ip_cand = [] additional_ip_cand = []
port = gajim.config.get('file_transfers_port') port = gajim.config.get('file_transfers_port')
ft_add_hosts = gajim.config.get('ft_add_hosts_to_send') ft_add_hosts = gajim.config.get('ft_add_hosts_to_send')
if ft_add_hosts: if ft_add_hosts:
hosts = [e.strip() for e in ft_add_hosts.split(',')] hosts = [e.strip() for e in ft_add_hosts.split(',')]
for h in hosts: for h in hosts:
@ -187,7 +200,7 @@ class JingleTransportSocks5(JingleTransport):
c['target'] = self.file_props['receiver'] c['target'] = self.file_props['receiver']
additional_ip_cand.append(c) additional_ip_cand.append(c)
self.candidates += additional_ip_cand self.candidates += additional_ip_cand
def _add_proxy_candidates(self): def _add_proxy_candidates(self):
if not self.connection: if not self.connection:
return return
@ -201,7 +214,7 @@ class JingleTransportSocks5(JingleTransport):
self.file_props['receiver']) self.file_props['receiver'])
self.file_props['proxy_sender'] = unicode(self.file_props['sender']) self.file_props['proxy_sender'] = unicode(self.file_props['sender'])
self.file_props['proxyhosts'] = proxyhosts self.file_props['proxyhosts'] = proxyhosts
for proxyhost in proxyhosts: for proxyhost in proxyhosts:
c = {'host': proxyhost['host']} c = {'host': proxyhost['host']}
c['candidate_id'] = self.connection.connection.getAnID() c['candidate_id'] = self.connection.connection.getAnID()
@ -213,7 +226,7 @@ class JingleTransportSocks5(JingleTransport):
c['target'] = self.file_props['receiver'] c['target'] = self.file_props['receiver']
proxy_cand.append(c) proxy_cand.append(c)
self.candidates += proxy_cand self.candidates += proxy_cand
def _on_proxy_auth_ok(self, proxy): def _on_proxy_auth_ok(self, proxy):
log.info('proxy auth ok for ' + str(proxy)) log.info('proxy auth ok for ' + str(proxy))
# send activate request to proxy, send activated confirmation to peer # send activate request to proxy, send activated confirmation to peer
@ -229,12 +242,12 @@ class JingleTransportSocks5(JingleTransport):
activate.setData(file_props['proxy_receiver']) activate.setData(file_props['proxy_receiver'])
iq.setID(auth_id) iq.setID(auth_id)
self.connection.connection.send(iq) self.connection.connection.send(iq)
content = xmpp.Node('content') content = xmpp.Node('content')
content.setAttr('creator', 'initiator') content.setAttr('creator', 'initiator')
content.setAttr('name', 'file') content.setAttr('name', 'file')
transport = xmpp.Node('transport') transport = xmpp.Node('transport')
transport.setAttr('xmlns', xmpp.NS_JINGLE_BYTESTREAM) transport.setNamespace(xmpp.NS_JINGLE_BYTESTREAM)
activated = xmpp.Node('activated') activated = xmpp.Node('activated')
cid = None cid = None
for host in self.candidates: for host in self.candidates:
@ -248,8 +261,9 @@ class JingleTransportSocks5(JingleTransport):
activated.setAttr('cid', cid) activated.setAttr('cid', cid)
transport.addChild(node=activated) transport.addChild(node=activated)
content.addChild(node=transport) content.addChild(node=transport)
sesn = self.connection.get_jingle_session(self.ourjid, self.file_props['sid']) sesn = self.connection.get_jingle_session(self.ourjid,
self.file_props['session-sid'])
if sesn is None: if sesn is None:
return return
sesn.send_transport_info(content) sesn.send_transport_info(content)
@ -257,7 +271,7 @@ class JingleTransportSocks5(JingleTransport):
import farsight import farsight
class JingleTransportICEUDP(JingleTransport): class JingleTransportICEUDP(JingleTransport):
def __init__(self): def __init__(self, node):
JingleTransport.__init__(self, TransportType.datagram) JingleTransport.__init__(self, TransportType.datagram)
def make_candidate(self, candidate): def make_candidate(self, candidate):

View File

@ -136,16 +136,16 @@ class ConnectionBytestream:
# file transfer initiated by a jingle session # file transfer initiated by a jingle session
log.info("send_file_approval: jingle session accept") log.info("send_file_approval: jingle session accept")
if file_props.get('session-type') == 'jingle': if file_props.get('session-type') == 'jingle':
session = self.get_jingle_session(file_props['sender'], file_props['sid']) session = self.get_jingle_session(file_props['sender'],
file_props['session-sid'])
if not session: if not session:
return return
sid = file_props['sid']
gajim.socks5queue.add_file_props(self.name, file_props) gajim.socks5queue.add_file_props(self.name, file_props)
if not session.accepted: if not session.accepted:
if session.get_content('file').use_security: if session.get_content('file').use_security:
id = jingle_xtls.send_cert_request(self, file_props['sender']) id_ = jingle_xtls.send_cert_request(self, file_props['sender'])
jingle_xtls.key_exchange_pend(id, session) jingle_xtls.key_exchange_pend(id_, session)
return return
session.approve_session() session.approve_session()
session.approve_content('file') session.approve_content('file')
@ -356,7 +356,7 @@ class ConnectionSocks5Bytestream(ConnectionBytestream):
if 'idx' in host and host['idx'] > 0: if 'idx' in host and host['idx'] > 0:
gajim.socks5queue.remove_receiver(host['idx']) gajim.socks5queue.remove_receiver(host['idx'])
gajim.socks5queue.remove_sender(host['idx']) gajim.socks5queue.remove_sender(host['idx'])
if 'direction' in file_props: if 'direction' in file_props:
# it's a IBB # it's a IBB
sid = file_props['sid'] sid = file_props['sid']
@ -822,7 +822,7 @@ class ConnectionIBBytestream(ConnectionBytestream):
{'sid':sid})])) {'sid':sid})]))
file_props['completed'] = True file_props['completed'] = True
del self.files_props[sid] del self.files_props[sid]
def IBBMessageHandler(self, conn, stanza): def IBBMessageHandler(self, conn, stanza):
""" """
Receive next portion of incoming datastream and store it write Receive next portion of incoming datastream and store it write

View File

@ -122,7 +122,8 @@ class SocksQueue:
return 1 return 1
return 0 return 0
def connect_to_hosts(self, account, sid, on_success=None, on_failure=None, fingerprint=None): def connect_to_hosts(self, account, sid, on_success=None, on_failure=None,
fingerprint=None):
self.on_success = on_success self.on_success = on_success
self.on_failure = on_failure self.on_failure = on_failure
file_props = self.files_props[account][sid] file_props = self.files_props[account][sid]
@ -130,7 +131,12 @@ class SocksQueue:
# add streamhosts to the queue # add streamhosts to the queue
for streamhost in file_props['streamhosts']: for streamhost in file_props['streamhosts']:
receiver = Socks5Receiver(self.idlequeue, streamhost, sid, file_props, fingerprint=fingerprint) if 'type' in streamhost and streamhost['type'] == 'proxy':
fp = None
else:
fd = fingerprint
receiver = Socks5Receiver(self.idlequeue, streamhost, sid,
file_props, fingerprint=fp)
self.add_receiver(account, receiver) self.add_receiver(account, receiver)
streamhost['idx'] = receiver.queue_idx streamhost['idx'] = receiver.queue_idx
@ -453,7 +459,7 @@ class Socks5:
received = '' received = ''
try: try:
add = self._recv(64) add = self._recv(64)
except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError, except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError,
OpenSSL.SSL.WantX509LookupError), e: OpenSSL.SSL.WantX509LookupError), e:
log.info('SSL rehandshake request : ' + repr(e)) log.info('SSL rehandshake request : ' + repr(e))
raise e raise e
@ -814,7 +820,7 @@ class Socks5Sender(Socks5, IdleObject):
self.queue.result_sha(self.sha_msg, self.queue_idx) self.queue.result_sha(self.sha_msg, self.queue_idx)
if result == -1: if result == -1:
self.disconnect() self.disconnect()
elif self.state == 5: elif self.state == 5:
if self.file_props is not None and self.file_props['type'] == 'r': if self.file_props is not None and self.file_props['type'] == 'r':
result = self.get_file_contents(0) result = self.get_file_contents(0)