diff options
Diffstat (limited to 'sleekxmpp')
-rw-r--r-- | sleekxmpp/plugins/xep_0065/proxy.py | 13 | ||||
-rw-r--r-- | sleekxmpp/stanza/iq.py | 15 | ||||
-rw-r--r-- | sleekxmpp/test/sleektest.py | 3 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/matcher/__init__.py | 1 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/matcher/idsender.py | 47 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/resolver.py | 70 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/xmlstream.py | 44 |
7 files changed, 119 insertions, 74 deletions
diff --git a/sleekxmpp/plugins/xep_0065/proxy.py b/sleekxmpp/plugins/xep_0065/proxy.py index 265d3030..fdd9f97e 100644 --- a/sleekxmpp/plugins/xep_0065/proxy.py +++ b/sleekxmpp/plugins/xep_0065/proxy.py @@ -88,8 +88,9 @@ class XEP_0065(base_plugin): # Request that the proxy activate the session with the target. self.activate(proxy, sid, to, timeout=timeout) - self.xmpp.event('stream:%s:%s' % (sid, conn.peer_jid), conn) - return self.get_socket(sid) + socket = self.get_socket(sid) + self.xmpp.event('stream:%s:%s' % (sid, to), socket) + return socket def request_stream(self, to, sid=None, ifrom=None, block=True, timeout=None, callback=None): if sid is None: @@ -198,11 +199,16 @@ class XEP_0065(base_plugin): sock = self._sessions.get(sid) if sock: try: + # sock.close() will also delete sid from self._sessions (see _connect_proxy) sock.close() except socket.error: pass + # Though this should not be neccessary remove the closed session anyway with self._sessions_lock: - del self._sessions[sid] + if sid in self._sessions: + log.warn(('SOCKS5 session with sid = "%s" was not ' + + 'removed from _sessions by sock.close()') % sid) + del self._sessions[sid] def close(self): """Closes all proxy sockets.""" @@ -250,6 +256,7 @@ class XEP_0065(base_plugin): if sid in self._sessions: del self._sessions[sid] _close() + log.info('Socket closed.') sock.close = close sock.peer_jid = peer diff --git a/sleekxmpp/stanza/iq.py b/sleekxmpp/stanza/iq.py index ba945e08..e377b82f 100644 --- a/sleekxmpp/stanza/iq.py +++ b/sleekxmpp/stanza/iq.py @@ -9,7 +9,7 @@ from sleekxmpp.stanza.rootstanza import RootStanza from sleekxmpp.xmlstream import StanzaBase, ET from sleekxmpp.xmlstream.handler import Waiter, Callback -from sleekxmpp.xmlstream.matcher import MatcherId +from sleekxmpp.xmlstream.matcher import MatchIDSender from sleekxmpp.exceptions import IqTimeout, IqError @@ -193,6 +193,13 @@ class Iq(RootStanza): """ if timeout is None: timeout = self.stream.response_timeout + + criteria = { + 'id': self['id'], + 'self': self.stream.boundjid, + 'peer': self['to'] + } + if callback is not None and self['type'] in ('get', 'set'): handler_name = 'IqCallback_%s' % self['id'] if timeout_callback: @@ -203,19 +210,19 @@ class Iq(RootStanza): self._fire_timeout, repeat=False) handler = Callback(handler_name, - MatcherId(self['id']), + MatchIDSender(criteria), self._handle_result, once=True) else: handler = Callback(handler_name, - MatcherId(self['id']), + MatchIDSender(criteria), callback, once=True) self.stream.register_handler(handler) StanzaBase.send(self, now=now) return handler_name elif block and self['type'] in ('get', 'set'): - waitfor = Waiter('IqWait_%s' % self['id'], MatcherId(self['id'])) + waitfor = Waiter('IqWait_%s' % self['id'], MatchIDSender(criteria)) self.stream.register_handler(waitfor) StanzaBase.send(self, now=now) result = waitfor.wait(timeout) diff --git a/sleekxmpp/test/sleektest.py b/sleekxmpp/test/sleektest.py index 04fb106d..51cda3ee 100644 --- a/sleekxmpp/test/sleektest.py +++ b/sleekxmpp/test/sleektest.py @@ -16,7 +16,7 @@ from sleekxmpp.test import TestSocket, TestLiveSocket from sleekxmpp.xmlstream import ET from sleekxmpp.xmlstream import ElementBase from sleekxmpp.xmlstream.tostring import tostring -from sleekxmpp.xmlstream.matcher import StanzaPath, MatcherId +from sleekxmpp.xmlstream.matcher import StanzaPath, MatcherId, MatchIDSender from sleekxmpp.xmlstream.matcher import MatchXMLMask, MatchXPath @@ -212,6 +212,7 @@ class SleekTest(unittest.TestCase): matchers = {'stanzapath': StanzaPath, 'xpath': MatchXPath, 'mask': MatchXMLMask, + 'idsender': MatchIDSender, 'id': MatcherId} Matcher = matchers.get(method, None) if Matcher is None: diff --git a/sleekxmpp/xmlstream/matcher/__init__.py b/sleekxmpp/xmlstream/matcher/__init__.py index 1038d1bd..aa74c434 100644 --- a/sleekxmpp/xmlstream/matcher/__init__.py +++ b/sleekxmpp/xmlstream/matcher/__init__.py @@ -7,6 +7,7 @@ """ from sleekxmpp.xmlstream.matcher.id import MatcherId +from sleekxmpp.xmlstream.matcher.idsender import MatchIDSender from sleekxmpp.xmlstream.matcher.many import MatchMany from sleekxmpp.xmlstream.matcher.stanzapath import StanzaPath from sleekxmpp.xmlstream.matcher.xmlmask import MatchXMLMask diff --git a/sleekxmpp/xmlstream/matcher/idsender.py b/sleekxmpp/xmlstream/matcher/idsender.py new file mode 100644 index 00000000..5c2c1f51 --- /dev/null +++ b/sleekxmpp/xmlstream/matcher/idsender.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +""" + sleekxmpp.xmlstream.matcher.id + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Part of SleekXMPP: The Sleek XMPP Library + + :copyright: (c) 2011 Nathanael C. Fritz + :license: MIT, see LICENSE for more details +""" + +from sleekxmpp.xmlstream.matcher.base import MatcherBase + + +class MatchIDSender(MatcherBase): + + """ + The IDSender matcher selects stanzas that have the same stanza 'id' + interface value as the desired ID, and that the 'from' value is one + of a set of approved entities that can respond to a request. + """ + + def match(self, xml): + """Compare the given stanza's ``'id'`` attribute to the stored + ``id`` value, and verify the sender's JID. + + :param xml: The :class:`~sleekxmpp.xmlstream.stanzabase.ElementBase` + stanza to compare against. + """ + + selfjid = self._criteria['self'] + peerjid = self._criteria['peer'] + + allowed = {} + allowed[''] = True + allowed[selfjid.bare] = True + allowed[selfjid.host] = True + allowed[peerjid.full] = True + allowed[peerjid.bare] = True + allowed[peerjid.host] = True + + _from = xml['from'] + + try: + return xml['id'] == self._criteria['id'] and allowed[_from] + except KeyError: + return False diff --git a/sleekxmpp/xmlstream/resolver.py b/sleekxmpp/xmlstream/resolver.py index 6f26797f..e82bfdb7 100644 --- a/sleekxmpp/xmlstream/resolver.py +++ b/sleekxmpp/xmlstream/resolver.py @@ -131,16 +131,16 @@ def resolve(host, port=None, service=None, proto='tcp', results.append((host, '::1', port)) results.append((host, '127.0.0.1', port)) if use_ipv6: - for address in get_AAAA(host, resolver=resolver): + for address in get_AAAA(host): results.append((host, address, port)) - for address in get_A(host, resolver=resolver): + for address in get_A(host): results.append((host, address, port)) for host, address, port in results: yield host, address, port -def get_A(host, resolver=None): +def get_A(host): """Lookup DNS A records for a given host. If ``resolver`` is not provided, or is ``None``, then resolution will @@ -158,32 +158,15 @@ def get_A(host, resolver=None): # If not using dnspython, attempt lookup using the OS level # getaddrinfo() method. - if resolver is None: - try: - recs = socket.getaddrinfo(host, None, socket.AF_INET, - socket.SOCK_STREAM) - return [rec[4][0] for rec in recs] - except socket.gaierror: - log.debug("DNS: Error retreiving A address info for %s." % host) - return [] - - # Using dnspython: try: - recs = resolver.query(host, dns.rdatatype.A) - return [rec.to_text() for rec in recs] - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): - log.debug("DNS: No A records for %s" % host) - return [] - except dns.exception.Timeout: - log.debug("DNS: A record resolution timed out for %s" % host) - return [] - except dns.exception.DNSException as e: - log.debug("DNS: Error querying A records for %s" % host) - log.exception(e) + recs = socket.getaddrinfo(host, None, socket.AF_INET, + socket.SOCK_STREAM) + return [rec[4][0] for rec in recs] + except socket.gaierror: + log.debug("DNS: Error retreiving A address info for %s." % host) return [] - -def get_AAAA(host, resolver=None): +def get_AAAA(host): """Lookup DNS AAAA records for a given host. If ``resolver`` is not provided, or is ``None``, then resolution will @@ -201,35 +184,18 @@ def get_AAAA(host, resolver=None): # If not using dnspython, attempt lookup using the OS level # getaddrinfo() method. - if resolver is None: - if not socket.has_ipv6: - log.debug("Unable to query %s for AAAA records: IPv6 is not supported", host) - return [] - try: - recs = socket.getaddrinfo(host, None, socket.AF_INET6, - socket.SOCK_STREAM) - return [rec[4][0] for rec in recs] - except (OSError, socket.gaierror): - log.debug("DNS: Error retreiving AAAA address " + \ - "info for %s." % host) - return [] - - # Using dnspython: - try: - recs = resolver.query(host, dns.rdatatype.AAAA) - return [rec.to_text() for rec in recs] - except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): - log.debug("DNS: No AAAA records for %s" % host) - return [] - except dns.exception.Timeout: - log.debug("DNS: AAAA record resolution timed out for %s" % host) + if not socket.has_ipv6: + log.debug("Unable to query %s for AAAA records: IPv6 is not supported", host) return [] - except dns.exception.DNSException as e: - log.debug("DNS: Error querying AAAA records for %s" % host) - log.exception(e) + try: + recs = socket.getaddrinfo(host, None, socket.AF_INET6, + socket.SOCK_STREAM) + return [rec[4][0] for rec in recs] + except (OSError, socket.gaierror): + log.debug("DNS: Error retreiving AAAA address " + \ + "info for %s." % host) return [] - def get_SRV(host, port, service, proto='tcp', resolver=None): """Perform SRV record resolution for a given host. diff --git a/sleekxmpp/xmlstream/xmlstream.py b/sleekxmpp/xmlstream/xmlstream.py index c503cdd2..3bc1f652 100644 --- a/sleekxmpp/xmlstream/xmlstream.py +++ b/sleekxmpp/xmlstream/xmlstream.py @@ -123,6 +123,11 @@ class XMLStream(object): #: xmpp.ssl_version = ssl.PROTOCOL_SSLv23 self.ssl_version = ssl.PROTOCOL_TLSv1 + #: The list of accepted ciphers, in OpenSSL Format. + #: It might be useful to override it for improved security + #: over the python defaults. + self.ciphers = None + #: Path to a file containing certificates for verifying the #: server SSL certificate. A non-``None`` value will trigger #: certificate checking. @@ -508,12 +513,18 @@ class XMLStream(object): else: cert_policy = ssl.CERT_REQUIRED - ssl_socket = ssl.wrap_socket(self.socket, - certfile=self.certfile, - keyfile=self.keyfile, - ca_certs=self.ca_certs, - cert_reqs=cert_policy, - do_handshake_on_connect=False) + ssl_args = { + 'certfile': self.certfile, + 'keyfile': self.keyfile, + 'ca_certs': self.ca_certs, + 'cert_reqs': cert_policy, + 'do_handshake_on_connect': False, + } + + if sys.version_info >= (2, 7): + ssl_args['ciphers'] = self.ciphers + + ssl_socket = ssl.wrap_socket(self.socket, **ssl_args) if hasattr(self.socket, 'socket'): # We are using a testing socket, so preserve the top @@ -826,13 +837,18 @@ class XMLStream(object): else: cert_policy = ssl.CERT_REQUIRED - ssl_socket = ssl.wrap_socket(self.socket, - certfile=self.certfile, - keyfile=self.keyfile, - ssl_version=self.ssl_version, - do_handshake_on_connect=False, - ca_certs=self.ca_certs, - cert_reqs=cert_policy) + ssl_args = { + 'certfile': self.certfile, + 'keyfile': self.keyfile, + 'ca_certs': self.ca_certs, + 'cert_reqs': cert_policy, + 'do_handshake_on_connect': False, + } + + if sys.version_info >= (2, 7): + ssl_args['ciphers'] = self.ciphers + + ssl_socket = ssl.wrap_socket(self.socket, **ssl_args); if hasattr(self.socket, 'socket'): # We are using a testing socket, so preserve the top @@ -1327,12 +1343,12 @@ class XMLStream(object): return True def _start_thread(self, name, target, track=True): - self.__active_threads.add(name) self.__thread[name] = threading.Thread(name=name, target=target) self.__thread[name].daemon = self._use_daemons self.__thread[name].start() if track: + self.__active_threads.add(name) with self.__thread_cond: self.__thread_count += 1 |